From 586c62819f6eb9a77978628afd53ba12c91a11e7 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Thu, 30 Mar 2023 11:09:11 +0100 Subject: [PATCH] aarch64; Add support for vector offset ranges Some SME2 instructions operate on a range of consecutive ZA vectors. This is indicated by syntax such as: za[, :] Like with the earlier vgx2 and vgx4 support, we get better error messages if the parser allows all ZA indices to have a range. We can then reject invalid cases during constraint checking. --- gas/config/tc-aarch64.c | 23 +++++++++ gas/testsuite/gas/aarch64/sme-2-illegal.l | 13 ++++++ gas/testsuite/gas/aarch64/sme-2-illegal.s | 7 +++ gas/testsuite/gas/aarch64/sme-5-illegal.l | 4 ++ gas/testsuite/gas/aarch64/sme-5-illegal.s | 3 ++ gas/testsuite/gas/aarch64/sme-6-illegal.l | 4 ++ gas/testsuite/gas/aarch64/sme-6-illegal.s | 3 ++ gas/testsuite/gas/aarch64/sme-7-illegal.l | 8 ++++ gas/testsuite/gas/aarch64/sme-7-illegal.s | 6 +++ gas/testsuite/gas/aarch64/sme-9-illegal.l | 9 ++++ gas/testsuite/gas/aarch64/sme-9-illegal.s | 4 ++ include/opcode/aarch64.h | 23 +++++++-- opcodes/aarch64-opc.c | 57 +++++++++++++++++++---- 13 files changed, 151 insertions(+), 13 deletions(-) diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c index 2d732ea1780..5873fc754a3 100644 --- a/gas/config/tc-aarch64.c +++ b/gas/config/tc-aarch64.c @@ -4550,6 +4550,29 @@ parse_sme_za_index (char **str, struct aarch64_indexed_za *opnd) return false; } + if (skip_past_char (str, ':')) + { + int64_t end; + if (!parse_sme_immediate (str, &end)) + { + set_syntax_error (_("expected a constant immediate offset")); + return false; + } + if (end < opnd->index.imm) + { + set_syntax_error (_("the last offset is less than the" + " first offset")); + return false; + } + if (end == opnd->index.imm) + { + set_syntax_error (_("the last offset is equal to the" + " first offset")); + return false; + } + opnd->index.countm1 = (uint64_t) end - opnd->index.imm; + } + opnd->group_size = 0; if (skip_past_char (str, ',')) { diff --git a/gas/testsuite/gas/aarch64/sme-2-illegal.l b/gas/testsuite/gas/aarch64/sme-2-illegal.l index fd36ed78381..71a104a2ecf 100644 --- a/gas/testsuite/gas/aarch64/sme-2-illegal.l +++ b/gas/testsuite/gas/aarch64/sme-2-illegal.l @@ -28,3 +28,16 @@ [^:]*:[0-9]+: Error: unexpected vector group size at operand 3 -- `mova z0.b,p0/m,za0h.b\[w12,#0,vgx2\]' [^:]*:[0-9]+: Error: unexpected vector group size at operand 3 -- `mova z0.b,p0/m,za0h.b\[w12,#0,vgx4\]' [^:]*:[0-9]+: Error: invalid vector group size at operand 3 -- `mova z0.b,p0/m,za0h.b\[w12,#0,vgx8\]' +[^:]*:[0-9]+: Error: the last offset is less than the first offset at operand 3 -- `mova z0.b,p0/m,za0h.b\[w12,1:0\]' +[^:]*:[0-9]+: Error: the last offset is equal to the first offset at operand 3 -- `mova z0.b,p0/m,za0h.b\[w12,0:0\]' +[^:]*:[0-9]+: Error: expected a single offset rather than a range at operand 3 -- `mova z0.b,p0/m,za0h.b\[w12,0:1\]' +[^:]*:[0-9]+: Error: expected a single offset rather than a range at operand 3 -- `mova z0.b,p0/m,za0h.b\[w12,0:2\]' +[^:]+:[0-9]+: Error: operand mismatch -- `mova z0\.b,p0/m,za0h\.h\[w12,0:1\]' +[^:]+:[0-9]+: Info: did you mean this\? +[^:]+:[0-9]+: Info: mova z0\.b, p0/m, za0h\.b\[w12, 0:1\] +[^:]+:[0-9]+: Info: other valid variant\(s\): +[^:]+:[0-9]+: Info: mova z0\.h, p0/m, za0h\.h\[w12, 0:1\] +[^:]+:[0-9]+: Info: mova z0\.s, p0/m, za0h\.s\[w12, 0:1\] +[^:]+:[0-9]+: Info: mova z0\.d, p0/m, za0h\.d\[w12, 0:1\] +[^:]+:[0-9]+: Info: mova z0\.q, p0/m, za0h\.q\[w12, 0:1\] +[^:]*:[0-9]+: Error: expected a constant immediate offset at operand 3 -- `mova z0.b,p0/m,za0h.b\[w12,0:foo\]' diff --git a/gas/testsuite/gas/aarch64/sme-2-illegal.s b/gas/testsuite/gas/aarch64/sme-2-illegal.s index 8cc130ac9c0..41bbe4e930b 100644 --- a/gas/testsuite/gas/aarch64/sme-2-illegal.s +++ b/gas/testsuite/gas/aarch64/sme-2-illegal.s @@ -34,3 +34,10 @@ mova z0.q, p0/m, za0v.q[w12, #1a2] mova z0.b, p0/m, za0h.b[w12, #0, vgx2] mova z0.b, p0/m, za0h.b[w12, #0, vgx4] mova z0.b, p0/m, za0h.b[w12, #0, vgx8] + +mova z0.b, p0/m, za0h.b[w12, 1:0] +mova z0.b, p0/m, za0h.b[w12, 0:0] +mova z0.b, p0/m, za0h.b[w12, 0:1] +mova z0.b, p0/m, za0h.b[w12, 0:2] +mova z0.b, p0/m, za0h.h[w12, 0:1] +mova z0.b, p0/m, za0h.b[w12, 0:foo] diff --git a/gas/testsuite/gas/aarch64/sme-5-illegal.l b/gas/testsuite/gas/aarch64/sme-5-illegal.l index f6eda9da5e2..c4bfc1f8b5a 100644 --- a/gas/testsuite/gas/aarch64/sme-5-illegal.l +++ b/gas/testsuite/gas/aarch64/sme-5-illegal.l @@ -62,3 +62,7 @@ [^:]*:[0-9]+: Error: operand mismatch -- `ld1b {za0h\.b\[w12,0,vgx4\]},p0/m,\[x0\]' [^:]*:[0-9]+: Info: did you mean this\? [^:]*:[0-9]+: Info: ld1b {za0h\.b\[w12, 0, vgx4\]}, p0/z, \[x0, xzr\] +[^:]*:[0-9]+: Error: expected a single offset rather than a range at operand 1 -- `ld1b {za0h\.b\[w12,0:1\]},p0/z,\[x0\]' +[^:]+:[0-9]+: Error: operand mismatch -- `ld1b {za0h\.b\[w12,0:1\]},p0/m,\[x0\]' +[^:]+:[0-9]+: Info: did you mean this\? +[^:]*:[0-9]+: Info: ld1b {za0h\.b\[w12, 0:1\]}, p0/z, \[x0, xzr\] diff --git a/gas/testsuite/gas/aarch64/sme-5-illegal.s b/gas/testsuite/gas/aarch64/sme-5-illegal.s index 9dbce626a6e..942a5cf9588 100644 --- a/gas/testsuite/gas/aarch64/sme-5-illegal.s +++ b/gas/testsuite/gas/aarch64/sme-5-illegal.s @@ -63,3 +63,6 @@ ld1b {za0h.b[w12, 0, vgx4]}, p0/z, [x0] ld1b {za0h.b[w12, 0, vgx8]}, p0/z, [x0] ld1b {za0h.b[w12, 0, vgx4]}, p0/m, [x0] + +ld1b {za0h.b[w12, 0:1]}, p0/z, [x0] +ld1b {za0h.b[w12, 0:1]}, p0/m, [x0] diff --git a/gas/testsuite/gas/aarch64/sme-6-illegal.l b/gas/testsuite/gas/aarch64/sme-6-illegal.l index bc0d19417fc..b98b76faaed 100644 --- a/gas/testsuite/gas/aarch64/sme-6-illegal.l +++ b/gas/testsuite/gas/aarch64/sme-6-illegal.l @@ -49,3 +49,7 @@ [^:]*:[0-9]+: Error: operand mismatch -- `st1b {za0h\.b\[w12,0,vgx2\]},p0/z,\[x0\]' [^:]*:[0-9]+: Info: did you mean this\? [^:]*:[0-9]+: Info: st1b {za0h\.b\[w12, 0, vgx2\]}, p0, \[x0, xzr\] +[^:]*:[0-9]+: Error: expected a single offset rather than a range at operand 1 -- `st1b {za0h\.b\[w12,0:1,vgx2\]},p0,\[x0\]' +[^:]+:[0-9]+: Error: operand mismatch -- `st1b {za0h\.b\[w12,0:1,vgx2\]},p0/m,\[x0\]' +[^:]+:[0-9]+: Info: did you mean this\? +[^:]*:[0-9]+: Info: st1b {za0h\.b\[w12, 0:1, vgx2\]}, p0, \[x0, xzr\] diff --git a/gas/testsuite/gas/aarch64/sme-6-illegal.s b/gas/testsuite/gas/aarch64/sme-6-illegal.s index 04a508821bc..bebbcb658e8 100644 --- a/gas/testsuite/gas/aarch64/sme-6-illegal.s +++ b/gas/testsuite/gas/aarch64/sme-6-illegal.s @@ -50,3 +50,6 @@ st1b {za0h.b[w12, 0, vgx4]}, p0, [x0] st1b {za0h.b[w12, 0, vgx8]}, p0, [x0] st1b {za0h.b[w12, 0, vgx2]}, p0/z, [x0] + +st1b {za0h.b[w12, 0:1, vgx2]}, p0, [x0] +st1b {za0h.b[w12, 0:1, vgx2]}, p0/m, [x0] diff --git a/gas/testsuite/gas/aarch64/sme-7-illegal.l b/gas/testsuite/gas/aarch64/sme-7-illegal.l index eb0c5e6f51a..5ab025cc27e 100644 --- a/gas/testsuite/gas/aarch64/sme-7-illegal.l +++ b/gas/testsuite/gas/aarch64/sme-7-illegal.l @@ -66,3 +66,11 @@ [^:]*:[0-9]+: Error: operand mismatch -- `str za\.b\[w12,0,vgx4\],\[x0\]' [^:]*:[0-9]+: Info: did you mean this\? [^:]*:[0-9]+: Info: str za\[w12, 0, vgx4\], \[x0\] +[^:]*:[0-9]+: Error: expected a single offset rather than a range at operand 1 -- `ldr za\[w12,0:1\],\[x0\]' +[^:]*:[0-9]+: Error: expected a single offset rather than a range at operand 1 -- `str za\[w12,0:2,vgx4\],\[x0\]' +[^:]*:[0-9]+: Error: operand mismatch -- `ldr za\.b\[w12,0:1\],\[x0\]' +[^:]*:[0-9]+: Info: did you mean this\? +[^:]*:[0-9]+: Info: ldr za\[w12, 0:1\], \[x0\] +[^:]*:[0-9]+: Error: operand mismatch -- `str za\.b\[w12,0:2,vgx4\],\[x0\]' +[^:]*:[0-9]+: Info: did you mean this\? +[^:]*:[0-9]+: Info: str za\[w12, 0:2, vgx4\], \[x0\] diff --git a/gas/testsuite/gas/aarch64/sme-7-illegal.s b/gas/testsuite/gas/aarch64/sme-7-illegal.s index 05d7d23fe29..7e97f910cf8 100644 --- a/gas/testsuite/gas/aarch64/sme-7-illegal.s +++ b/gas/testsuite/gas/aarch64/sme-7-illegal.s @@ -63,3 +63,9 @@ str za[w12, 0, vgx8], [x0] ldr za.b[w12, 0, vgx2], [x0] str za.b[w12, 0, vgx4], [x0] + +ldr za[w12, 0:1], [x0] +str za[w12, 0:2, vgx4], [x0] + +ldr za.b[w12, 0:1], [x0] +str za.b[w12, 0:2, vgx4], [x0] diff --git a/gas/testsuite/gas/aarch64/sme-9-illegal.l b/gas/testsuite/gas/aarch64/sme-9-illegal.l index d7aff825288..7f44435ef08 100644 --- a/gas/testsuite/gas/aarch64/sme-9-illegal.l +++ b/gas/testsuite/gas/aarch64/sme-9-illegal.l @@ -37,6 +37,15 @@ [^:]*:[0-9]+: Info: psel p0, p0, p0\.h\[w12, 0\] [^:]*:[0-9]+: Info: psel p0, p0, p0\.s\[w12, 0\] [^:]*:[0-9]+: Info: psel p0, p0, p0\.d\[w12, 0\] +[^:]*:[0-9]+: Error: expected a single offset rather than a range at operand 3 -- `psel p0,p0,p0\.b\[w12,0:1\]' +[^:]*:[0-9]+: Error: expected a single offset rather than a range at operand 3 -- `psel p0,p0,p0\.b\[w12,0:1,vgx2\]' +[^:]*:[0-9]+: Error: operand mismatch -- `psel p0\.b,p0\.b,p0\.b\[w12,0:1,vgx2\]' +[^:]*:[0-9]+: Info: did you mean this\? +[^:]*:[0-9]+: Info: psel p0, p0, p0\.b\[w12, 0\] +[^:]*:[0-9]+: Info: other valid variant\(s\): +[^:]*:[0-9]+: Info: psel p0, p0, p0\.h\[w12, 0\] +[^:]*:[0-9]+: Info: psel p0, p0, p0\.s\[w12, 0\] +[^:]*:[0-9]+: Info: psel p0, p0, p0\.d\[w12, 0\] [^:]*:[0-9]+: Error: operand mismatch -- `revd z0.q,p0/m,z0.b' [^:]*:[0-9]+: Info: did you mean this\? [^:]*:[0-9]+: Info: revd z0.q, p0/m, z0.q diff --git a/gas/testsuite/gas/aarch64/sme-9-illegal.s b/gas/testsuite/gas/aarch64/sme-9-illegal.s index 8f41298cd3c..3c07e2d6fcb 100644 --- a/gas/testsuite/gas/aarch64/sme-9-illegal.s +++ b/gas/testsuite/gas/aarch64/sme-9-illegal.s @@ -23,6 +23,10 @@ psel p0, p0, p0.b[w12, #0, vgx8] psel p0.b, p0.b, p0.b[w12, #0, vgx2] +psel p0, p0, p0.b[w12, 0:1] +psel p0, p0, p0.b[w12, 0:1, vgx2] +psel p0.b, p0.b, p0.b[w12, 0:1, vgx2] + revd z0.q, p0/m, z0.b sclamp z8.b, z1.b, z31.q diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h index 534bdaa869f..7ccbb0eda7c 100644 --- a/include/opcode/aarch64.h +++ b/include/opcode/aarch64.h @@ -1114,14 +1114,29 @@ const aarch64_cond* get_inverted_cond (const aarch64_cond *cond); /* Information about a reference to part of ZA. */ struct aarch64_indexed_za { - int regno; /* */ + /* Which tile is being accessed. Unused (and 0) for an index into ZA. */ + int regno; + struct { - int regno; /* */ - int64_t imm; /* */ + /* The 32-bit index register. */ + int regno; + + /* The first (or only) immediate offset. */ + int64_t imm; + + /* The last immediate offset minus the first immediate offset. + Unlike the range size, this is guaranteed not to overflow + when the end offset > the start offset. */ + uint64_t countm1; } index; + + /* The vector group size, or 0 if none. */ unsigned group_size : 8; - unsigned v : 1; /* horizontal or vertical vector indicator. */ + + /* True if a tile access is vertical, false if it is horizontal. + Unused (and 0) for an index into ZA. */ + unsigned v : 1; }; /* Information about a list of registers. */ diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c index 0d38ff250c4..4df1dc2cda8 100644 --- a/opcodes/aarch64-opc.c +++ b/opcodes/aarch64-opc.c @@ -1527,14 +1527,18 @@ check_reglist (const aarch64_opnd_info *opnd, - a selection register in the range [MIN_WREG, MIN_WREG + 3] - - an immediate offset in the range [0, MAX_VALUE]. + - RANGE_SIZE consecutive immediate offsets. + + - an initial immediate offset that is a multiple of RANGE_SIZE + in the range [0, MAX_VALUE * RANGE_SIZE] - a vector group size of GROUP_SIZE. */ static bool check_za_access (const aarch64_opnd_info *opnd, aarch64_operand_error *mismatch_detail, int idx, - int min_wreg, int max_value, int group_size) + int min_wreg, int max_value, unsigned int range_size, + int group_size) { if (!value_in_range_p (opnd->indexed_za.index.regno, min_wreg, min_wreg + 3)) { @@ -1547,9 +1551,31 @@ check_za_access (const aarch64_opnd_info *opnd, return false; } - if (!value_in_range_p (opnd->indexed_za.index.imm, 0, max_value)) + int max_index = max_value * range_size; + if (!value_in_range_p (opnd->indexed_za.index.imm, 0, max_index)) + { + set_offset_out_of_range_error (mismatch_detail, idx, 0, max_index); + return false; + } + + if ((opnd->indexed_za.index.imm % range_size) != 0) + { + assert (range_size == 2 || range_size == 4); + set_other_error (mismatch_detail, idx, + range_size == 2 + ? _("starting offset is not a multiple of 2") + : _("starting offset is not a multiple of 4")); + return false; + } + + if (opnd->indexed_za.index.countm1 != range_size - 1) { - set_offset_out_of_range_error (mismatch_detail, idx, 0, max_value); + if (range_size == 1) + set_other_error (mismatch_detail, idx, + _("expected a single offset rather than" + " a range")); + else + abort (); return false; } @@ -1678,7 +1704,8 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx, case AARCH64_OPND_SME_PnT_Wm_imm: size = aarch64_get_qualifier_esize (opnd->qualifier); max_value = 16 / size - 1; - if (!check_za_access (opnd, mismatch_detail, idx, 12, max_value, 0)) + if (!check_za_access (opnd, mismatch_detail, idx, + 12, max_value, 1, 0)) return 0; break; @@ -1701,13 +1728,13 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx, case AARCH64_OPND_SME_ZA_HV_idx_ldstr: size = aarch64_get_qualifier_esize (opnd->qualifier); max_value = 16 / size - 1; - if (!check_za_access (opnd, mismatch_detail, idx, 12, max_value, + if (!check_za_access (opnd, mismatch_detail, idx, 12, max_value, 1, get_opcode_dependent_value (opcode))) return 0; break; case AARCH64_OPND_SME_ZA_array_off4: - if (!check_za_access (opnd, mismatch_detail, idx, 12, 15, + if (!check_za_access (opnd, mismatch_detail, idx, 12, 15, 1, get_opcode_dependent_value (opcode))) return 0; break; @@ -3694,7 +3721,7 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc, case AARCH64_OPND_SME_ZA_HV_idx_src: case AARCH64_OPND_SME_ZA_HV_idx_dest: case AARCH64_OPND_SME_ZA_HV_idx_ldstr: - snprintf (buf, size, "%s%s[%s, %s%s%s]%s", + snprintf (buf, size, "%s%s[%s, %s%s%s%s%s]%s", opnd->type == AARCH64_OPND_SME_ZA_HV_idx_ldstr ? "{" : "", style_reg (styler, "za%d%c.%s", opnd->indexed_za.regno, @@ -3702,6 +3729,12 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc, aarch64_get_qualifier_name (opnd->qualifier)), style_reg (styler, "w%d", opnd->indexed_za.index.regno), style_imm (styler, "%" PRIi64, opnd->indexed_za.index.imm), + opnd->indexed_za.index.countm1 ? ":" : "", + (opnd->indexed_za.index.countm1 + ? style_imm (styler, "%d", + opnd->indexed_za.index.imm + + opnd->indexed_za.index.countm1) + : ""), opnd->indexed_za.group_size ? ", " : "", opnd->indexed_za.group_size == 2 ? style_sub_mnem (styler, "vgx2") @@ -3715,10 +3748,16 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc, break; case AARCH64_OPND_SME_ZA_array_off4: - snprintf (buf, size, "%s[%s, %s%s%s]", + snprintf (buf, size, "%s[%s, %s%s%s%s%s]", style_reg (styler, "za"), style_reg (styler, "w%d", opnd->indexed_za.index.regno), style_imm (styler, "%" PRIi64, opnd->indexed_za.index.imm), + opnd->indexed_za.index.countm1 ? ":" : "", + (opnd->indexed_za.index.countm1 + ? style_imm (styler, "%d", + opnd->indexed_za.index.imm + + opnd->indexed_za.index.countm1) + : ""), opnd->indexed_za.group_size ? ", " : "", opnd->indexed_za.group_size == 2 ? style_sub_mnem (styler, "vgx2") -- 2.30.2