aarch64: Rework reporting of failed register checks
authorRichard Sandiford <richard.sandiford@arm.com>
Thu, 30 Mar 2023 10:09:06 +0000 (11:09 +0100)
committerRichard Sandiford <richard.sandiford@arm.com>
Thu, 30 Mar 2023 10:09:06 +0000 (11:09 +0100)
commite426521ed1f44468cf0d8418f3f29a856af70b25
tree6c529285ec467309f03b0df29abfab9c626c274b
parent405f0c4131cbdf540d9e9559ba5d6e4f445a3818
aarch64: Rework reporting of failed register checks

There are many opcode table entries that share the same mnemonic.
Trying to parse an invalid assembly line will trigger an error for
each of these entries, but the specific error might vary from one
entry to another, depending on the exact nature of the problem.

GAS has quite an elaborate system for picking the most appropriate
error out of all the failed matches.  And in many cases it works well.
However, one of the limitations is that the error is always reported
against a single opcode table entry.  If that table entry isn't the
one that the user intended to use, then the error can end up being
overly specific.

This is particularly true if an instruction has a typoed register
name, or uses a type of register that is not accepted by any
opcode table entry.  For example, one of the expected error
matches for an attempted SVE2 instruction is:

  Error: operand 1 must be a SIMD scalar register -- `addp z32\.s,p0/m,z32\.s,z0\.s'

even though the hypothetical user was presumably attempting to use
the SVE form of ADDP rather than the Advanced SIMD one.  There are
many other instances of this in the testsuite.

The problem becomes especially acute with SME2, since many SME2
instructions reuse existing mnemonics.  This could lead to us
reporting an SME-related error against a non-SME instruction,
or a non-SME-related error against an SME instruction.

This patch tries to improve things by collecting together all
the register types that an opcode table entry expected for a
given operand.  It also records what kind of register was
actually seen, if any.  It then tries to summarise all this
in a more directed way, falling back to a generic error if
the combination defies a neat summary.

The patch includes tests for all new messages except REG_TYPE_ZA,
which only triggers with SME2.

To test this, I created an assembly file that contained the cross
product of all known mnemonics and one example from each register
class.  I then looked for cases where the new routines fell back on the
generic errors ("expected a register" or "unexpected register type").
I locally added dummy messages for each one until there were no
more hits.  The patch adds a specimen instruction to diagnostics.s
for each of these combinations.  In each case, the combination didn't
seem like something that could be summarised in a natural way, so the
generic messages seemed better.  There's always going to be an element
of personal taste around this kind of thing though.

Adding more register types made 1<<REG_TYPE_MAX exceed the range
of the type, but we don't actually need/want 1<<REG_TYPE_MAX.
23 files changed:
gas/config/tc-aarch64.c
gas/testsuite/gas/aarch64/armv8_2-a-crypto-fp16-illegal.l
gas/testsuite/gas/aarch64/diagnostic.l
gas/testsuite/gas/aarch64/diagnostic.s
gas/testsuite/gas/aarch64/illegal-bfloat16.l
gas/testsuite/gas/aarch64/illegal-fjcvtzs.l
gas/testsuite/gas/aarch64/illegal-memtag.l
gas/testsuite/gas/aarch64/illegal-sve2.l
gas/testsuite/gas/aarch64/legacy_reg_names.l
gas/testsuite/gas/aarch64/mops_invalid.l
gas/testsuite/gas/aarch64/sme-2-illegal.l
gas/testsuite/gas/aarch64/sme-3-illegal.l
gas/testsuite/gas/aarch64/sme-4-illegal.l
gas/testsuite/gas/aarch64/sme-5-illegal.l
gas/testsuite/gas/aarch64/sme-5-illegal.s
gas/testsuite/gas/aarch64/sme-6-illegal.l
gas/testsuite/gas/aarch64/sme-7-illegal.l
gas/testsuite/gas/aarch64/sme-7-illegal.s
gas/testsuite/gas/aarch64/sme-illegal.l
gas/testsuite/gas/aarch64/sme-illegal.s
gas/testsuite/gas/aarch64/sve-invalid.l
gas/testsuite/gas/aarch64/sve-reg-diagnostic.l
gas/testsuite/gas/aarch64/tme-invalid.l