Many SME2 instructions operate on groups of 2 or 4 ZA vectors.
This is indicated by adding a "vgx2" or "vgx4" group size to the
ZA index. The group size is optional in assembly but preferred
for disassembly.
There is not a binary distinction between mnemonics that have
group sizes and mnemonics that don't, nor between mnemonics that
take vgx2 and mnemonics that take vgx4. We therefore get better
error messages if we allow any ZA index to have a group size
during parsing, and wait until constraint checking to reject
invalid sizes.
A quirk of the way errors are reported means that if an instruction
is wrong both in its qualifiers and its use of a group size, we'll
print suggested alternative instructions that also have an incorrect
group size. But that's a general property that also applies to
things like out-of-range immediates. It's also not obviously the
wrong thing to do. We need to be relatively confident that we're
looking at the right opcode before reporting detailed operand-specific
errors, so doing qualifier checking first seems resonable.
return false;
}
+ opnd->group_size = 0;
+ if (skip_past_char (str, ','))
+ {
+ if (strncasecmp (*str, "vgx2", 4) == 0 && !ISALPHA ((*str)[4]))
+ {
+ *str += 4;
+ opnd->group_size = 2;
+ }
+ else if (strncasecmp (*str, "vgx4", 4) == 0 && !ISALPHA ((*str)[4]))
+ {
+ *str += 4;
+ opnd->group_size = 4;
+ }
+ else
+ {
+ set_syntax_error (_("invalid vector group size"));
+ return false;
+ }
+ }
+
if (!skip_past_char (str, ']'))
{
set_syntax_error (_("expected ']'"));
"AARCH64_OPDE_SYNTAX_ERROR",
"AARCH64_OPDE_FATAL_SYNTAX_ERROR",
"AARCH64_OPDE_INVALID_VARIANT",
+ "AARCH64_OPDE_INVALID_VG_SIZE",
"AARCH64_OPDE_REG_LIST_LENGTH",
"AARCH64_OPDE_REG_LIST_STRIDE",
"AARCH64_OPDE_UNTIED_IMMS",
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_LENGTH > AARCH64_OPDE_INVALID_VARIANT);
+ gas_assert (AARCH64_OPDE_INVALID_VG_SIZE > AARCH64_OPDE_INVALID_VARIANT);
+ gas_assert (AARCH64_OPDE_REG_LIST_LENGTH > AARCH64_OPDE_INVALID_VG_SIZE);
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);
detail->data[0].i, idx + 1, str);
break;
+ case AARCH64_OPDE_INVALID_VG_SIZE:
+ if (detail->data[0].i == 0)
+ handler (_("unexpected vector group size at operand %d -- `%s'"),
+ idx + 1, str);
+ else
+ handler (_("operand %d must have a vector group size of %d -- `%s'"),
+ idx + 1, detail->data[0].i, str);
+ break;
+
case AARCH64_OPDE_REG_LIST_LENGTH:
if (detail->data[0].i == (1 << 1))
handler (_("expected a single-register list at operand %d -- `%s'"),
[^:]*:[0-9]+: Error: expected '\]' at operand 3 -- `mova z0\.q,p0/m,za0v\.q\[w12,#1a\]'
[^:]*:[0-9]+: Error: expected '\]' at operand 3 -- `mova z0\.q,p0/m,za0v\.q\[w12,1a2\]'
[^:]*:[0-9]+: Error: expected '\]' at operand 3 -- `mova z0\.q,p0/m,za0v\.q\[w12,#1a2\]'
+[^:]*:[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\]'
mova z0.q, p0/m, za0v.q[w12, #1a]
mova z0.q, p0/m, za0v.q[w12, 1a2]
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]
[^:]*:[0-9]+: Error: immediate offset out of range 0 to 3 at operand 1 -- `mova za3v\.s\[w15,#4\],p7/m,z31.s'
[^:]*:[0-9]+: Error: immediate offset out of range 0 to 1 at operand 1 -- `mova za7v\.d\[w15,#2\],p7/m,z31.d'
[^:]*:[0-9]+: Error: immediate offset must be 0 at operand 1 -- `mova za15v\.q\[w15,#1\],p7/m,z31.q'
+[^:]*:[0-9]+: Error: unexpected vector group size at operand 1 -- `mova za0h\.b\[w12,#0,vgx2\],p0/m,z0\.b'
+[^:]*:[0-9]+: Error: unexpected vector group size at operand 1 -- `mova za0h\.b\[w12,#0,vgx4\],p0/m,z0\.b'
+[^:]*:[0-9]+: Error: invalid vector group size at operand 1 -- `mova za0h\.b\[w12,#0,vgx8\],p0/m,z0\.b'
+[^:]*:[0-9]+: Error: operand mismatch -- `mova za0h\.b\[w12,#0,vgx2\],p0/z,z0\.b'
+[^:]*:[0-9]+: Info: did you mean this\?
+[^:]*:[0-9]+: Info: mova za0h\.b\[w12, 0, vgx2\], p0/m, z0\.b
+[^:]*:[0-9]+: Info: other valid variant\(s\):
+[^:]*:[0-9]+: Info: mova za0h\.h\[w12, 0, vgx2\], p0/m, z0\.h
+[^:]*:[0-9]+: Info: mova za0h\.s\[w12, 0, vgx2\], p0/m, z0\.s
+[^:]*:[0-9]+: Info: mova za0h\.d\[w12, 0, vgx2\], p0/m, z0\.d
+[^:]*:[0-9]+: Info: mova za0h\.q\[w12, 0, vgx2\], p0/m, z0\.q
mova za3v.s[w15, #4], p7/m, z31.s
mova za7v.d[w15, #2], p7/m, z31.d
mova za15v.q[w15, #1], p7/m, z31.q
+
+mova za0h.b[w12, #0, vgx2], p0/m, z0.b
+mova za0h.b[w12, #0, vgx4], p0/m, z0.b
+mova za0h.b[w12, #0, vgx8], p0/m, z0.b
+
+mova za0h.b[w12, #0, vgx2], p0/z, z0.b
[^:]*:[0-9]+: Error: missing braces at operand 1 -- `ld1w za0h.s\[w12,0\],p0/z,\[x0\]'
[^:]*:[0-9]+: Error: missing braces at operand 1 -- `ld1d za0h.d\[w12,0\],p0/z,\[x0\]'
[^:]*:[0-9]+: Error: missing braces at operand 1 -- `ld1q za0h.q\[w12,0\],p0/z,\[x0\]'
+[^:]*:[0-9]+: Error: unexpected vector group size at operand 1 -- `ld1b {za0h\.b\[w12,0,vgx2\]},p0/z,\[x0\]'
+[^:]*:[0-9]+: Error: unexpected vector group size at operand 1 -- `ld1b {za0h\.b\[w12,0,vgx4\]},p0/z,\[x0\]'
+[^:]*:[0-9]+: Error: invalid vector group size at operand 1 -- `ld1b {za0h\.b\[w12,0,vgx8\]},p0/z,\[x0\]'
+[^:]*:[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\]
ld1w za0h.s[w12, 0], p0/z, [x0]
ld1d za0h.d[w12, 0], p0/z, [x0]
ld1q za0h.q[w12, 0], p0/z, [x0]
+
+ld1b {za0h.b[w12, 0, vgx2]}, p0/z, [x0]
+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]
[^:]*:[0-9]+: Error: immediate offset must be 0 at operand 1 -- `st1q {za15h.q\[w15,1\]},p7,\[sp\]'
[^:]*:[0-9]+: Error: immediate offset must be 0 at operand 1 -- `st1q {za15v.q\[w15,1\]},p7,\[x0,x17,lsl#4\]'
[^:]*:[0-9]+: Error: immediate offset must be 0 at operand 1 -- `st1q {za15h.q\[w15,1\]},p7,\[sp,x17,lsl#4\]'
+[^:]*:[0-9]+: Error: unexpected vector group size at operand 1 -- `st1b {za0h.b\[w12,0,vgx2\]},p0,\[x0\]'
+[^:]*:[0-9]+: Error: unexpected vector group size at operand 1 -- `st1b {za0h\.b\[w12,0,vgx4\]},p0,\[x0\]'
+[^:]*:[0-9]+: Error: invalid vector group size at operand 1 -- `st1b {za0h\.b\[w12,0,vgx8\]},p0,\[x0\]'
+[^:]*:[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\]
st1q {za15h.q[w15, 1]}, p7, [sp]
st1q {za15v.q[w15, 1]}, p7, [x0, x17, lsl #4]
st1q {za15h.q[w15, 1]}, p7, [sp, x17, lsl #4]
+
+st1b {za0h.b[w12, 0, vgx2]}, p0, [x0]
+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]
[^:]*:[0-9]+: Error: expected 'za' rather than a ZA tile at operand 1 -- `ldr za0h.h\[w12,0\],\[x0\]'
[^:]*:[0-9]+: Error: expected 'za' rather than a ZA tile at operand 1 -- `ldr za0v\[w12,0\],\[x0\]'
[^:]*:[0-9]+: Error: expected 'za' rather than a ZA tile at operand 1 -- `ldr za0v.s\[w12,0\],\[x0\]'
+[^:]*:[0-9]+: Error: unexpected vector group size at operand 1 -- `ldr za\[w12,0,vgx2\],\[x0\]'
+[^:]*:[0-9]+: Error: unexpected vector group size at operand 1 -- `ldr za\[w12,0,vgx4\],\[x0\]'
+[^:]*:[0-9]+: Error: invalid vector group size at operand 1 -- `ldr za\[w12,0,vgx8\],\[x0\]'
+[^:]*:[0-9]+: Error: unexpected vector group size at operand 1 -- `str za\[w12,0,vgx2\],\[x0\]'
+[^:]*:[0-9]+: Error: unexpected vector group size at operand 1 -- `str za\[w12,0,vgx4\],\[x0\]'
+[^:]*:[0-9]+: Error: invalid vector group size at operand 1 -- `str za\[w12,0,vgx8\],\[x0\]'
+[^:]*:[0-9]+: Error: operand mismatch -- `ldr za\.b\[w12,0,vgx2\],\[x0\]'
+[^:]*:[0-9]+: Info: did you mean this\?
+[^:]*:[0-9]+: Info: ldr za\[w12, 0, vgx2\], \[x0\]
+[^:]*:[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\]
ldr za0h.h[w12, 0], [x0]
ldr za0v[w12, 0], [x0]
ldr za0v.s[w12, 0], [x0]
+
+ldr za[w12, 0, vgx2], [x0]
+ldr za[w12, 0, vgx4], [x0]
+ldr za[w12, 0, vgx8], [x0]
+
+str za[w12, 0, vgx2], [x0]
+str za[w12, 0, vgx4], [x0]
+str za[w12, 0, vgx8], [x0]
+
+ldr za.b[w12, 0, vgx2], [x0]
+str za.b[w12, 0, vgx4], [x0]
[^:]*:[0-9]+: Error: immediate offset out of range 0 to 7 at operand 3 -- `psel p1,p8,p6.h\[w14,#8\]'
[^:]*:[0-9]+: Error: immediate offset out of range 0 to 3 at operand 3 -- `psel p8,p4,p15.s\[w13,#4\]'
[^:]*:[0-9]+: Error: immediate offset out of range 0 to 1 at operand 3 -- `psel p1,p1,p1.d\[w12,#2\]'
+[^:]*:[0-9]+: Error: unexpected vector group size at operand 3 -- `psel p0,p0,p0\.b\[w12,#0,vgx2\]'
+[^:]*:[0-9]+: Error: unexpected vector group size at operand 3 -- `psel p0,p0,p0\.b\[w12,#0,vgx4\]'
+[^:]*:[0-9]+: Error: invalid vector group size at operand 3 -- `psel p0,p0,p0\.b\[w12,#0,vgx8\]'
+[^:]*:[0-9]+: Error: operand mismatch -- `psel p0\.b,p0\.b,p0\.b\[w12,#0,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
psel p8, p4, p15.s[w13, #4]
psel p1, p1, p1.d[w12, #2]
+psel p0, p0, p0.b[w12, #0, vgx2]
+psel p0, p0, p0.b[w12, #0, vgx4]
+psel p0, p0, p0.b[w12, #0, vgx8]
+
+psel p0.b, p0.b, p0.b[w12, #0, vgx2]
+
revd z0.q, p0/m, z0.b
sclamp z8.b, z1.b, z31.q
int regno; /* <Wv> */
int64_t imm; /* <imm> */
} index;
+ unsigned group_size : 8;
unsigned v : 1; /* <HV> horizontal or vertical vector indicator. */
};
The following errors are only reported against an asm string that is
syntactically valid and that has valid operand qualifiers.
+ AARCH64_OPDE_INVALID_VG_SIZE
+ Error about a "VGx<n>" modifier in a ZA index not having the
+ correct <n>. This error effectively forms a pair with
+ AARCH64_OPDE_REG_LIST_LENGTH, since both errors relate to the number
+ of vectors that an instruction operates on. However, the "VGx<n>"
+ modifier is optional, whereas a register list always has a known
+ and explicit length. It therefore seems better to place more
+ importance on the register list length when selecting an opcode table
+ entry. This in turn means that having an incorrect register length
+ should be more severe than having an incorrect "VGx<n>".
+
AARCH64_OPDE_REG_LIST_LENGTH
Error about a register list operand having an unexpected number of
registers. This error is low severity because there might be another
AARCH64_OPDE_SYNTAX_ERROR,
AARCH64_OPDE_FATAL_SYNTAX_ERROR,
AARCH64_OPDE_INVALID_VARIANT,
+ AARCH64_OPDE_INVALID_VG_SIZE,
AARCH64_OPDE_REG_LIST_LENGTH,
AARCH64_OPDE_REG_LIST_STRIDE,
AARCH64_OPDE_UNTIED_IMMS,
mismatch_detail->data[0].i = 1 << expected_num;
}
+static inline void
+set_invalid_vg_size (aarch64_operand_error *mismatch_detail,
+ int idx, int expected)
+{
+ if (mismatch_detail == NULL)
+ return;
+ set_error (mismatch_detail, AARCH64_OPDE_INVALID_VG_SIZE, idx, NULL);
+ mismatch_detail->data[0].i = expected;
+}
+
static inline void
set_other_error (aarch64_operand_error *mismatch_detail, int idx,
const char* error)
- a selection register in the range [MIN_WREG, MIN_WREG + 3]
- - an immediate offset in the range [0, MAX_VALUE]. */
+ - an immediate offset in the range [0, MAX_VALUE].
+
+ - 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 min_wreg, int max_value, int group_size)
{
if (!value_in_range_p (opnd->indexed_za.index.regno, min_wreg, min_wreg + 3))
{
set_offset_out_of_range_error (mismatch_detail, idx, 0, max_value);
return false;
}
+
+ /* The vector group specifier is optional in assembly code. */
+ if (opnd->indexed_za.group_size != 0
+ && opnd->indexed_za.group_size != group_size)
+ {
+ set_invalid_vg_size (mismatch_detail, idx, group_size);
+ return false;
+ }
+
return true;
}
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))
+ if (!check_za_access (opnd, mismatch_detail, idx, 12, max_value, 0))
return 0;
break;
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,
+ 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,
+ get_opcode_dependent_value (opcode)))
return 0;
break;
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",
+ snprintf (buf, size, "%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,
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.group_size ? ", " : "",
+ opnd->indexed_za.group_size == 2
+ ? style_sub_mnem (styler, "vgx2")
+ : opnd->indexed_za.group_size == 4
+ ? style_sub_mnem (styler, "vgx4") : "",
opnd->type == AARCH64_OPND_SME_ZA_HV_idx_ldstr ? "}" : "");
break;
break;
case AARCH64_OPND_SME_ZA_array_off4:
- snprintf (buf, size, "%s[%s, %s]",
+ snprintf (buf, size, "%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));
+ style_imm (styler, "%" PRIi64, opnd->indexed_za.index.imm),
+ opnd->indexed_za.group_size ? ", " : "",
+ opnd->indexed_za.group_size == 2
+ ? style_sub_mnem (styler, "vgx2")
+ : opnd->indexed_za.group_size == 4
+ ? style_sub_mnem (styler, "vgx4") : "");
break;
case AARCH64_OPND_SME_SM_ZA: