diff options
author | Richard Sandiford <richard.sandiford@arm.com> | 2021-12-02 15:00:57 +0000 |
---|---|---|
committer | Richard Sandiford <richard.sandiford@arm.com> | 2021-12-02 15:00:57 +0000 |
commit | 63eff947512b36c770c92d45e4b22cb8a18a39be (patch) | |
tree | 336e8d9a01ee6665d9ec7b8148155ee7cab992a0 /gas/config | |
parent | 6327658ee73502ffb55dfb6b28a20d1dde15a4dc (diff) | |
download | gdb-63eff947512b36c770c92d45e4b22cb8a18a39be.zip gdb-63eff947512b36c770c92d45e4b22cb8a18a39be.tar.gz gdb-63eff947512b36c770c92d45e4b22cb8a18a39be.tar.bz2 |
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.
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/tc-aarch64.c | 38 |
1 files changed, 28 insertions, 10 deletions
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c index 4aadf5b..ea65da5 100644 --- a/gas/config/tc-aarch64.c +++ b/gas/config/tc-aarch64.c @@ -5019,6 +5019,8 @@ const char* operand_mismatch_kind_names[] = { "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", @@ -5040,7 +5042,10 @@ operand_error_higher_severity_p (enum aarch64_operand_error_kind lhs, enum aarch64_operand_error_kind rhs) { gas_assert (AARCH64_OPDE_RECOVERABLE > AARCH64_OPDE_NIL); - gas_assert (AARCH64_OPDE_SYNTAX_ERROR > AARCH64_OPDE_RECOVERABLE); + gas_assert (AARCH64_OPDE_A_SHOULD_FOLLOW_B > AARCH64_OPDE_RECOVERABLE); + gas_assert (AARCH64_OPDE_EXPECTED_A_AFTER_B > AARCH64_OPDE_RECOVERABLE); + gas_assert (AARCH64_OPDE_SYNTAX_ERROR > AARCH64_OPDE_A_SHOULD_FOLLOW_B); + 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_OUT_OF_RANGE > AARCH64_OPDE_INVALID_VARIANT); @@ -5233,9 +5238,9 @@ record_operand_error_with_data (const aarch64_opcode *opcode, int idx, info.index = idx; info.kind = kind; info.error = error; - info.data[0] = extra_data[0]; - info.data[1] = extra_data[1]; - info.data[2] = extra_data[2]; + info.data[0].i = extra_data[0]; + info.data[1].i = extra_data[1]; + info.data[2].i = extra_data[2]; info.non_fatal = false; record_operand_error_info (opcode, &info); } @@ -5410,6 +5415,19 @@ output_operand_error_record (const operand_error_record *record, char *str) case AARCH64_OPDE_NIL: gas_assert (0); break; + + case AARCH64_OPDE_A_SHOULD_FOLLOW_B: + handler (_("this `%s' should have an immediately preceding `%s'" + " -- `%s'"), + detail->data[0].s, detail->data[1].s, str); + break; + + case AARCH64_OPDE_EXPECTED_A_AFTER_B: + handler (_("the preceding `%s' should be followed by `%s` rather" + " than `%s` -- `%s'"), + detail->data[1].s, detail->data[0].s, opcode->name, str); + break; + case AARCH64_OPDE_SYNTAX_ERROR: case AARCH64_OPDE_RECOVERABLE: case AARCH64_OPDE_FATAL_SYNTAX_ERROR: @@ -5541,31 +5559,31 @@ output_operand_error_record (const operand_error_record *record, char *str) break; case AARCH64_OPDE_OUT_OF_RANGE: - if (detail->data[0] != detail->data[1]) + if (detail->data[0].i != detail->data[1].i) handler (_("%s out of range %d to %d at operand %d -- `%s'"), detail->error ? detail->error : _("immediate value"), - detail->data[0], detail->data[1], idx + 1, str); + detail->data[0].i, detail->data[1].i, idx + 1, str); else handler (_("%s must be %d at operand %d -- `%s'"), detail->error ? detail->error : _("immediate value"), - detail->data[0], idx + 1, str); + detail->data[0].i, idx + 1, str); break; case AARCH64_OPDE_REG_LIST: - if (detail->data[0] == 1) + if (detail->data[0].i == 1) handler (_("invalid number of registers in the list; " "only 1 register is expected at operand %d -- `%s'"), idx + 1, str); else handler (_("invalid number of registers in the list; " "%d registers are expected at operand %d -- `%s'"), - detail->data[0], idx + 1, str); + detail->data[0].i, idx + 1, str); break; case AARCH64_OPDE_UNALIGNED: handler (_("immediate value must be a multiple of " "%d at operand %d -- `%s'"), - detail->data[0], idx + 1, str); + detail->data[0].i, idx + 1, str); break; default: |