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 | |
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')
-rw-r--r-- | gas/config/tc-aarch64.c | 38 | ||||
-rw-r--r-- | gas/testsuite/gas/aarch64/mops_invalid_2.d | 72 | ||||
-rw-r--r-- | gas/testsuite/gas/aarch64/mops_invalid_2.l | 27 | ||||
-rw-r--r-- | gas/testsuite/gas/aarch64/mops_invalid_2.s | 75 |
4 files changed, 202 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: diff --git a/gas/testsuite/gas/aarch64/mops_invalid_2.d b/gas/testsuite/gas/aarch64/mops_invalid_2.d new file mode 100644 index 0000000..f5e7228 --- /dev/null +++ b/gas/testsuite/gas/aarch64/mops_invalid_2.d @@ -0,0 +1,72 @@ +# warning_output: mops_invalid_2.l +# objdump: -dr -M notes + +.* + + +Disassembly of section \.text: + +0+ <\.text>: +[^:]*: 1901d440 cpyfpwtn \[x0\]!, \[x1\]!, x2! +[^:]*: 1981d440 cpyfewtn \[x0\]!, \[x1\]!, x2! // note: expected `cpyfmwtn' after previous `cpyfpwtn' +[^:]*: 1941d440 cpyfmwtn \[x0\]!, \[x1\]!, x2! // note: this `cpyfmwtn' should have an immediately preceding `cpyfpwtn' +[^:]*: 1901d440 cpyfpwtn \[x0\]!, \[x1\]!, x2! +[^:]*: 1941f440 cpyfmtn \[x0\]!, \[x1\]!, x2! // note: expected `cpyfmwtn' after previous `cpyfpwtn' +[^:]*: 1981f440 cpyfetn \[x0\]!, \[x1\]!, x2! +[^:]*: 1d010440 cpyp \[x0\]!, \[x1\]!, x2! +[^:]*: 19c24420 setm \[x0\]!, x1!, x2 // note: expected `cpym' after previous `cpyp' +[^:]*: 19c28420 sete \[x0\]!, x1!, x2 +[^:]*: 19011440 cpyfpwt \[x0\]!, \[x1\]!, x2! +[^:]*: 19411443 cpyfmwt \[x3\]!, \[x1\]!, x2! // note: destination register differs from preceding instruction at operand 1 +[^:]*: 19811444 cpyfewt \[x4\]!, \[x1\]!, x2! // note: destination register differs from preceding instruction at operand 1 +[^:]*: 19011440 cpyfpwt \[x0\]!, \[x1\]!, x2! +[^:]*: 19431440 cpyfmwt \[x0\]!, \[x3\]!, x2! // note: source register differs from preceding instruction at operand 2 +[^:]*: 19841440 cpyfewt \[x0\]!, \[x4\]!, x2! // note: source register differs from preceding instruction at operand 2 +[^:]*: 19011440 cpyfpwt \[x0\]!, \[x1\]!, x2! +[^:]*: 19411460 cpyfmwt \[x0\]!, \[x1\]!, x3! // note: size register differs from preceding instruction at operand 3 +[^:]*: 19811480 cpyfewt \[x0\]!, \[x1\]!, x4! // note: size register differs from preceding instruction at operand 3 +[^:]*: 1901d440 cpyfpwtn \[x0\]!, \[x1\]!, x2! +[^:]*: 8b020020 add x0, x1, x2 // note: expected `cpyfmwtn' after previous `cpyfpwtn' +[^:]*: 1901e440 cpyfprtn \[x0\]!, \[x1\]!, x2! +[^:]*: 1941e440 cpyfmrtn \[x0\]!, \[x1\]!, x2! + +Disassembly of section \.text2: + +0+ <\.text2>: +[^:]*: 1901d440 cpyfpwtn \[x0\]!, \[x1\]!, x2! // note: instruction opens new dependency sequence without ending previous one + +Disassembly of section \.text3: + +0+ <\.text3>: +[^:]*: 1941d440 cpyfmwtn \[x0\]!, \[x1\]!, x2! // note: this `cpyfmwtn' should have an immediately preceding `cpyfpwtn' + +Disassembly of section \.text4: + +0+ <\.text4>: +[^:]*: 1981d440 cpyfewtn \[x0\]!, \[x1\]!, x2! // note: this `cpyfewtn' should have an immediately preceding `cpyfmwtn' +[^:]*: 19014440 cpyfpwn \[x0\]!, \[x1\]!, x2! + +Disassembly of section \.text5: + +0+ <\.text5>: +[^:]*: 91000020 add x0, x1, #0x0 // note: expected `cpyfmwn' after previous `cpyfpwn' +[^:]*: 19c20420 setp \[x0\]!, x1!, x2 +[^:]*: 19c28420 sete \[x0\]!, x1!, x2 // note: expected `setm' after previous `setp' +[^:]*: 19c24420 setm \[x0\]!, x1!, x2 // note: this `setm' should have an immediately preceding `setp' +[^:]*: 19c20420 setp \[x0\]!, x1!, x2 +[^:]*: 19c24423 setm \[x3\]!, x1!, x2 // note: destination register differs from preceding instruction at operand 1 +[^:]*: 19c28424 sete \[x4\]!, x1!, x2 // note: destination register differs from preceding instruction at operand 1 +[^:]*: 19c20420 setp \[x0\]!, x1!, x2 +[^:]*: 19c24460 setm \[x0\]!, x3!, x2 // note: size register differs from preceding instruction at operand 2 +[^:]*: 19c28480 sete \[x0\]!, x4!, x2 // note: size register differs from preceding instruction at operand 2 +[^:]*: 19c20420 setp \[x0\]!, x1!, x2 +[^:]*: 19c44420 setm \[x0\]!, x1!, x4 +[^:]*: 19c38420 sete \[x0\]!, x1!, x3 +[^:]*: 0420bc20 movprfx z0, z1 +[^:]*: 19c24420 setm \[x0\]!, x1!, x2 // note: SVE instruction expected after `movprfx' +[^:]*: 19c20420 setp \[x0\]!, x1!, x2 +[^:]*: 0420bc20 movprfx z0, z1 // note: instruction opens new dependency sequence without ending previous one +[^:]*: 65808080 fadd z0\.s, p0/m, z0\.s, z4\.s +[^:]*: 19c20420 setp \[x0\]!, x1!, x2 +[^:]*: 0420bc20 movprfx z0, z1 // note: instruction opens new dependency sequence without ending previous one +[^:]*: 65808082 fadd z2\.s, p0/m, z2\.s, z4\.s // note: output register of preceding `movprfx' not used in current instruction at operand 1 diff --git a/gas/testsuite/gas/aarch64/mops_invalid_2.l b/gas/testsuite/gas/aarch64/mops_invalid_2.l new file mode 100644 index 0000000..4f75753 --- /dev/null +++ b/gas/testsuite/gas/aarch64/mops_invalid_2.l @@ -0,0 +1,27 @@ +[^:]*: Assembler messages: +[^:]*:4: Warning: the preceding `cpyfpwtn' should be followed by `cpyfmwtn` rather than `cpyfewtn` -- `cpyfewtn \[x0\]!,\[x1\]!,x2!' +[^:]*:5: Warning: this `cpyfmwtn' should have an immediately preceding `cpyfpwtn' -- `cpyfmwtn \[x0\]!,\[x1\]!,x2!' +[^:]*:8: Warning: the preceding `cpyfpwtn' should be followed by `cpyfmwtn` rather than `cpyfmtn` -- `cpyfmtn \[x0\]!,\[x1\]!,x2!' +[^:]*:12: Warning: the preceding `cpyp' should be followed by `cpym` rather than `setm` -- `setm \[x0\]!,x1!,x2' +[^:]*:16: Warning: destination register differs from preceding instruction at operand 1 -- `cpyfmwt \[x3\]!,\[x1\]!,x2!' +[^:]*:17: Warning: destination register differs from preceding instruction at operand 1 -- `cpyfewt \[x4\]!,\[x1\]!,x2!' +[^:]*:20: Warning: source register differs from preceding instruction at operand 2 -- `cpyfmwt \[x0\]!,\[x3\]!,x2!' +[^:]*:21: Warning: source register differs from preceding instruction at operand 2 -- `cpyfewt \[x0\]!,\[x4\]!,x2!' +[^:]*:24: Warning: size register differs from preceding instruction at operand 3 -- `cpyfmwt \[x0\]!,\[x1\]!,x3!' +[^:]*:25: Warning: size register differs from preceding instruction at operand 3 -- `cpyfewt \[x0\]!,\[x1\]!,x4!' +[^:]*:28: Warning: the preceding `cpyfpwtn' should be followed by `cpyfmwtn` rather than `add` -- `add x0,x1,x2' +[^:]*:39: Warning: this `cpyfmwtn' should have an immediately preceding `cpyfpwtn' -- `cpyfmwtn \[x0\]!,\[x1\]!,x2!' +[^:]*:43: Warning: this `cpyfewtn' should have an immediately preceding `cpyfmwtn' -- `cpyfewtn \[x0\]!,\[x1\]!,x2!' +[^:]*:51: Warning: the preceding `setp' should be followed by `setm` rather than `sete` -- `sete \[x0\]!,x1!,x2' +[^:]*:52: Warning: this `setm' should have an immediately preceding `setp' -- `setm \[x0\]!,x1!,x2' +[^:]*:55: Warning: destination register differs from preceding instruction at operand 1 -- `setm \[x3\]!,x1!,x2' +[^:]*:56: Warning: destination register differs from preceding instruction at operand 1 -- `sete \[x4\]!,x1!,x2' +[^:]*:59: Warning: size register differs from preceding instruction at operand 2 -- `setm \[x0\]!,x3!,x2' +[^:]*:60: Warning: size register differs from preceding instruction at operand 2 -- `sete \[x0\]!,x4!,x2' +[^:]*:67: Warning: SVE instruction expected after `movprfx' -- `setm \[x0\]!,x1!,x2' +[^:]*:70: Warning: instruction opens new dependency sequence without ending previous one -- `movprfx z0,z1' +[^:]*:74: Warning: instruction opens new dependency sequence without ending previous one -- `movprfx z0,z1' +[^:]*:75: Warning: output register of preceding `movprfx' not used in current instruction at operand 1 -- `fadd z2\.s,p0/m,z2\.s,z4\.s' +[^:]*:31: Warning: previous `cpyfprtn' sequence has not been closed +[^:]*:35: Warning: previous `cpyfpwtn' sequence has not been closed +[^:]*:44: Warning: previous `cpyfpwn' sequence has not been closed diff --git a/gas/testsuite/gas/aarch64/mops_invalid_2.s b/gas/testsuite/gas/aarch64/mops_invalid_2.s new file mode 100644 index 0000000..f78ca54 --- /dev/null +++ b/gas/testsuite/gas/aarch64/mops_invalid_2.s @@ -0,0 +1,75 @@ + .arch armv8.8-a+sve + + cpyfpwtn [x0]!, [x1]!, x2! + cpyfewtn [x0]!, [x1]!, x2! + cpyfmwtn [x0]!, [x1]!, x2! + + cpyfpwtn [x0]!, [x1]!, x2! + cpyfmtn [x0]!, [x1]!, x2! + cpyfetn [x0]!, [x1]!, x2! + + cpyp [x0]!, [x1]!, x2! + setm [x0]!, x1!, x2 + sete [x0]!, x1!, x2 + + cpyfpwt [x0]!, [x1]!, x2! + cpyfmwt [x3]!, [x1]!, x2! + cpyfewt [x4]!, [x1]!, x2! + + cpyfpwt [x0]!, [x1]!, x2! + cpyfmwt [x0]!, [x3]!, x2! + cpyfewt [x0]!, [x4]!, x2! + + cpyfpwt [x0]!, [x1]!, x2! + cpyfmwt [x0]!, [x1]!, x3! + cpyfewt [x0]!, [x1]!, x4! + + cpyfpwtn [x0]!, [x1]!, x2! + add x0, x1, x2 + + cpyfprtn [x0]!, [x1]!, x2! + cpyfmrtn [x0]!, [x1]!, x2! + + .section .text2, "ax", @progbits + + cpyfpwtn [x0]!, [x1]!, x2! + + .section .text3, "ax", @progbits + + cpyfmwtn [x0]!, [x1]!, x2! + + .section .text4, "ax", @progbits + + cpyfewtn [x0]!, [x1]!, x2! + cpyfpwn [x0]!, [x1]!, x2! + + .section .text5, "ax", @progbits + + add x0, x1, #0 + + setp [x0]!, x1!, x2 + sete [x0]!, x1!, x2 + setm [x0]!, x1!, x2 + + setp [x0]!, x1!, x2 + setm [x3]!, x1!, x2 + sete [x4]!, x1!, x2 + + setp [x0]!, x1!, x2 + setm [x0]!, x3!, x2 + sete [x0]!, x4!, x2 + + setp [x0]!, x1!, x2 + setm [x0]!, x1!, x4 // OK + sete [x0]!, x1!, x3 // OK + + movprfx z0, z1 + setm [x0]!, x1!, x2 + + setp [x0]!, x1!, x2 + movprfx z0, z1 + fadd z0.s, p0/m, z0.s, z4.s + + setp [x0]!, x1!, x2 + movprfx z0, z1 + fadd z2.s, p0/m, z2.s, z4.s |