aarch64: Enforce P/M/E order for MOPS instructions

The MOPS instructions should be used as a triple, such as:

       cpyfp [x0]!, [x1]!, x2!
       cpyfm [x0]!, [x1]!, x2!
       cpyfe [x0]!, [x1]!, x2!

The registers should also be the same for each writeback operand.
This patch adds a warning for code that doesn't follow this rule,
along similar lines to the warning that we already emit for
invalid uses of MOVPRFX.

include/
	* opcode/aarch64.h (C_SCAN_MOPS_P, C_SCAN_MOPS_M, C_SCAN_MOPS_E)
	(C_SCAN_MOPS_PME): New macros.
	(AARCH64_OPDE_A_SHOULD_FOLLOW_B): New aarch64_operand_error_kind.
	(AARCH64_OPDE_EXPECTED_A_AFTER_B): Likewise.
	(aarch64_operand_error): Make each data value a union between
	an int and a string.

opcodes/
	* aarch64-tbl.h (MOPS_CPY_OP1_OP2_INSN): Add scan flags.
	(MOPS_SET_OP1_OP2_INSN): Likewise.
	* aarch64-opc.c (set_out_of_range_error): Update after change to
	aarch64_operand_error.
	(set_unaligned_error, set_reg_list_error): Likewise.
	(init_insn_sequence): Use a 3-instruction sequence for
	MOPS P instructions.
	(verify_mops_pme_sequence): New function.
	(verify_constraints): Call it.
	* aarch64-dis.c (print_verifier_notes): Handle
	AARCH64_OPDE_A_SHOULD_FOLLOW_B and AARCH64_OPDE_EXPECTED_A_AFTER_B.

gas/
	* config/tc-aarch64.c (operand_mismatch_kind_names): Add entries
	for AARCH64_OPDE_A_SHOULD_FOLLOW_B and AARCH64_OPDE_EXPECTED_A_AFTER_B.
	(operand_error_higher_severity_p): Check that
	AARCH64_OPDE_A_SHOULD_FOLLOW_B and AARCH64_OPDE_EXPECTED_A_AFTER_B
	come between AARCH64_OPDE_RECOVERABLE and AARCH64_OPDE_SYNTAX_ERROR;
	their relative order is not significant.
	(record_operand_error_with_data): Update after change to
	aarch64_operand_error.
	(output_operand_error_record): Likewise.  Handle
	AARCH64_OPDE_A_SHOULD_FOLLOW_B and AARCH64_OPDE_EXPECTED_A_AFTER_B.
	* testsuite/gas/aarch64/mops_invalid_2.s,
	testsuite/gas/aarch64/mops_invalid_2.d,
	testsuite/gas/aarch64/mops_invalid_2.l: New test.
This commit is contained in:
Richard Sandiford
2021-12-02 15:00:57 +00:00
parent 6327658ee7
commit 63eff94751
8 changed files with 354 additions and 32 deletions

View File

@@ -927,7 +927,11 @@ extern const aarch64_opcode aarch64_opcode_table[];
/* This instruction's operation width is determined by the operand with the
largest element size. */
#define C_MAX_ELEM (1U << 1)
/* Next bit is 2. */
#define C_SCAN_MOPS_P (1U << 2)
#define C_SCAN_MOPS_M (2U << 2)
#define C_SCAN_MOPS_E (3U << 2)
#define C_SCAN_MOPS_PME (3U << 2)
/* Next bit is 4. */
static inline bool
alias_opcode_p (const aarch64_opcode *opcode)
@@ -1221,6 +1225,17 @@ struct aarch64_inst
Less severe error found during the parsing, very possibly because that
GAS has picked up a wrong instruction template for the parsing.
AARCH64_OPDE_A_SHOULD_FOLLOW_B
The instruction forms (or is expected to form) part of a sequence,
but the preceding instruction in the sequence wasn't the expected one.
The message refers to two strings: the name of the current instruction,
followed by the name of the expected preceding instruction.
AARCH64_OPDE_EXPECTED_A_AFTER_B
Same as AARCH64_OPDE_A_SHOULD_FOLLOW_B, but shifting the focus
so that the current instruction is assumed to be the incorrect one:
"since the previous instruction was B, the current one should be A".
AARCH64_OPDE_SYNTAX_ERROR
General syntax error; it can be either a user error, or simply because
that GAS is trying a wrong instruction template.
@@ -1255,11 +1270,8 @@ struct aarch64_inst
Error of the highest severity and used for any severe issue that does not
fall into any of the above categories.
The enumerators are only interesting to GAS. They are declared here (in
libopcodes) because that some errors are detected (and then notified to GAS)
by libopcodes (rather than by GAS solely).
The first three errors are only deteced by GAS while the
AARCH64_OPDE_RECOVERABLE, AARCH64_OPDE_SYNTAX_ERROR and
AARCH64_OPDE_FATAL_SYNTAX_ERROR are only deteced by GAS while the
AARCH64_OPDE_INVALID_VARIANT error can only be spotted by libopcodes as
only libopcodes has the information about the valid variants of each
instruction.
@@ -1273,6 +1285,8 @@ enum aarch64_operand_error_kind
{
AARCH64_OPDE_NIL,
AARCH64_OPDE_RECOVERABLE,
AARCH64_OPDE_A_SHOULD_FOLLOW_B,
AARCH64_OPDE_EXPECTED_A_AFTER_B,
AARCH64_OPDE_SYNTAX_ERROR,
AARCH64_OPDE_FATAL_SYNTAX_ERROR,
AARCH64_OPDE_INVALID_VARIANT,
@@ -1290,7 +1304,11 @@ struct aarch64_operand_error
enum aarch64_operand_error_kind kind;
int index;
const char *error;
int data[3]; /* Some data for extra information. */
/* Some data for extra information. */
union {
int i;
const char *s;
} data[3];
bool non_fatal;
};