From 9af8f6711831f2851bf88c46a1f0f2a43fb49be8 Mon Sep 17 00:00:00 2001 From: Victor Do Nascimento Date: Mon, 20 Nov 2023 20:40:10 +0000 Subject: [PATCH] aarch64: Add support for 128-bit system register mrrs and msrr insns With the addition of 128-bit system registers to the Arm architecture starting with Armv9.4-a, a mechanism for manipulating their contents is introduced with the `msrr' and `mrrs' instruction pair. These move values from one such 128-bit system register into a pair of contiguous general-purpose registers and vice-versa, as for example: msrr ttlb0_el1, x0, x1 mrrs x0, x1, ttlb0_el1 This patch adds the necessary support for these instructions, adding checks for system-register width by defining a new operand type in the form of `AARCH64_OPND_SYSREG128' and the `aarch64_sys_reg_128bit_p' predicate, responsible for checking whether the requested system register table entry is marked as implemented in the 128-bit mode via the F_REG_128 flag. --- gas/config/tc-aarch64.c | 13 +++++++++---- gas/testsuite/gas/aarch64/illegal-sysreg128.d | 2 ++ gas/testsuite/gas/aarch64/illegal-sysreg128.l | 11 +++++++++++ gas/testsuite/gas/aarch64/illegal-sysreg128.s | 8 ++++++++ gas/testsuite/gas/aarch64/sysreg128.d | 28 +++++++++++++++++++++++++++ gas/testsuite/gas/aarch64/sysreg128.s | 17 ++++++++++++++++ include/opcode/aarch64.h | 2 ++ opcodes/aarch64-dis.c | 1 + opcodes/aarch64-opc.c | 9 ++++++++- opcodes/aarch64-tbl.h | 3 +++ 10 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 gas/testsuite/gas/aarch64/illegal-sysreg128.d create mode 100644 gas/testsuite/gas/aarch64/illegal-sysreg128.l create mode 100644 gas/testsuite/gas/aarch64/illegal-sysreg128.s create mode 100644 gas/testsuite/gas/aarch64/sysreg128.d create mode 100644 gas/testsuite/gas/aarch64/sysreg128.s diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c index 6a8ebe4..6d8c356 100644 --- a/gas/config/tc-aarch64.c +++ b/gas/config/tc-aarch64.c @@ -4788,7 +4788,7 @@ parse_sme_sm_za (char **str) static int parse_sys_reg (char **str, htab_t sys_regs, int imple_defined_p, int pstatefield_p, - uint32_t* flags) + uint32_t* flags, bool sysreg128_p) { char *p, *q; char buf[AARCH64_MAX_SYSREG_NAME_LEN]; @@ -4838,6 +4838,9 @@ parse_sys_reg (char **str, htab_t sys_regs, &o->features)) as_bad (_("selected processor does not support system register " "name '%s'"), buf); + if (sysreg128_p && !aarch64_sys_reg_128bit_p (o->flags)) + as_bad (_("128-bit-wide accsess not allowed on selected system" + " register '%s'"), buf); if (aarch64_sys_reg_deprecated_p (o->flags)) as_warn (_("system register name '%s' is deprecated and may be " "removed in a future release"), buf); @@ -7616,12 +7619,14 @@ parse_operands (char *str, const aarch64_opcode *opcode) } info->qualifier = base_qualifier; goto regoff_addr; - case AARCH64_OPND_SYSREG: + case AARCH64_OPND_SYSREG128: { + bool sysreg128_p = operands[i] == AARCH64_OPND_SYSREG128; uint32_t sysreg_flags; if ((val = parse_sys_reg (&str, aarch64_sys_regs_hsh, 1, 0, - &sysreg_flags)) == PARSE_FAIL) + &sysreg_flags, + sysreg128_p)) == PARSE_FAIL) { set_syntax_error (_("unknown or missing system register name")); goto failure; @@ -7635,7 +7640,7 @@ parse_operands (char *str, const aarch64_opcode *opcode) { uint32_t sysreg_flags; if ((val = parse_sys_reg (&str, aarch64_pstatefield_hsh, 0, 1, - &sysreg_flags)) == PARSE_FAIL) + &sysreg_flags, false)) == PARSE_FAIL) { set_syntax_error (_("unknown or missing PSTATE field name")); goto failure; diff --git a/gas/testsuite/gas/aarch64/illegal-sysreg128.d b/gas/testsuite/gas/aarch64/illegal-sysreg128.d new file mode 100644 index 0000000..05bafec --- /dev/null +++ b/gas/testsuite/gas/aarch64/illegal-sysreg128.d @@ -0,0 +1,2 @@ +#name: Instruction validation testing for mrrs and msrr. +#error_output: illegal-sysreg128.l diff --git a/gas/testsuite/gas/aarch64/illegal-sysreg128.l b/gas/testsuite/gas/aarch64/illegal-sysreg128.l new file mode 100644 index 0000000..a7d06b7 --- /dev/null +++ b/gas/testsuite/gas/aarch64/illegal-sysreg128.l @@ -0,0 +1,11 @@ +.*: Assembler messages: +.*: Error: 128-bit-wide accsess not allowed on selected system register 'accdata_el1' +.*: Error: 128-bit-wide accsess not allowed on selected system register 'accdata_el1' +.*: Error: operand mismatch -- `mrrs w0,w1,ttbr0_el1' +.*: Info: did you mean this\? +.*: Info: mrrs x0, x1, ttbr0_el1 +.*: Error: operand mismatch -- `msrr ttbr0_el1,w0,w1' +.*: Info: did you mean this\? +.*: Info: msrr ttbr0_el1, x0, x1 +.*: Error: reg pair must be contiguous at operand 2 -- `mrrs x0,x2,ttbr0_el1' +.*: Error: reg pair must be contiguous at operand 3 -- `msrr ttbr0_el1,x0,x2' diff --git a/gas/testsuite/gas/aarch64/illegal-sysreg128.s b/gas/testsuite/gas/aarch64/illegal-sysreg128.s new file mode 100644 index 0000000..90dcfef --- /dev/null +++ b/gas/testsuite/gas/aarch64/illegal-sysreg128.s @@ -0,0 +1,8 @@ + .arch armv8.1-a+d128 + + mrrs x0, x1, accdata_el1 + msrr accdata_el1, x0, x1 + mrrs w0, w1, ttbr0_el1 + msrr ttbr0_el1, w0, w1 + mrrs x0, x2, ttbr0_el1 + msrr ttbr0_el1, x0, x2 diff --git a/gas/testsuite/gas/aarch64/sysreg128.d b/gas/testsuite/gas/aarch64/sysreg128.d new file mode 100644 index 0000000..8c9f7ca --- /dev/null +++ b/gas/testsuite/gas/aarch64/sysreg128.d @@ -0,0 +1,28 @@ +#objdump: -dr + +.* + + +Disassembly of section \.text: + +0+ <\.text>: +[^:]*: d5787402 mrrs x2, x3, par_el1 +[^:]*: d5587404 msrr par_el1, x4, x5 +[^:]*: d578d0c2 mrrs x2, x3, rcwmask_el1 +[^:]*: d558d0c4 msrr rcwmask_el1, x4, x5 +[^:]*: d578d062 mrrs x2, x3, rcwsmask_el1 +[^:]*: d558d064 msrr rcwsmask_el1, x4, x5 +[^:]*: d5782002 mrrs x2, x3, ttbr0_el1 +[^:]*: d5582004 msrr ttbr0_el1, x4, x5 +[^:]*: d57d2002 mrrs x2, x3, ttbr0_el12 +[^:]*: d55d2004 msrr ttbr0_el12, x4, x5 +[^:]*: d57c2002 mrrs x2, x3, ttbr0_el2 +[^:]*: d55c2004 msrr ttbr0_el2, x4, x5 +[^:]*: d5782022 mrrs x2, x3, ttbr1_el1 +[^:]*: d5582024 msrr ttbr1_el1, x4, x5 +[^:]*: d57d2022 mrrs x2, x3, ttbr1_el12 +[^:]*: d55d2024 msrr ttbr1_el12, x4, x5 +[^:]*: d57c2022 mrrs x2, x3, ttbr1_el2 +[^:]*: d55c2024 msrr ttbr1_el2, x4, x5 +[^:]*: d57c2102 mrrs x2, x3, vttbr_el2 +[^:]*: d55c2104 msrr vttbr_el2, x4, x5 \ No newline at end of file diff --git a/gas/testsuite/gas/aarch64/sysreg128.s b/gas/testsuite/gas/aarch64/sysreg128.s new file mode 100644 index 0000000..4093315 --- /dev/null +++ b/gas/testsuite/gas/aarch64/sysreg128.s @@ -0,0 +1,17 @@ + .arch armv9.4-a+d128+the + + .macro rwreg128, name + mrrs x2, x3, \name + msrr \name, x4, x5 + .endm + + rwreg128 par_el1 + rwreg128 rcwmask_el1 + rwreg128 rcwsmask_el1 + rwreg128 ttbr0_el1 + rwreg128 ttbr0_el12 + rwreg128 ttbr0_el2 + rwreg128 ttbr1_el1 + rwreg128 ttbr1_el12 + rwreg128 ttbr1_el2 + rwreg128 vttbr_el2 diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h index 768caec..a459887 100644 --- a/include/opcode/aarch64.h +++ b/include/opcode/aarch64.h @@ -561,6 +561,7 @@ enum aarch64_opnd AARCH64_OPND_SIMD_ADDR_POST, /* Address of ld/st multiple post-indexed. */ AARCH64_OPND_SYSREG, /* System register operand. */ + AARCH64_OPND_SYSREG128, /* 128-bit system register operand. */ AARCH64_OPND_PSTATEFIELD, /* PSTATE field name operand. */ AARCH64_OPND_SYSREG_AT, /* System register operand. */ AARCH64_OPND_SYSREG_DC, /* System register operand. */ @@ -1328,6 +1329,7 @@ typedef struct extern const aarch64_sys_reg aarch64_sys_regs []; extern const aarch64_sys_reg aarch64_pstatefields []; extern bool aarch64_sys_reg_deprecated_p (const uint32_t); +extern bool aarch64_sys_reg_128bit_p (const uint32_t); extern bool aarch64_sys_reg_alias_p (const uint32_t); extern bool aarch64_pstatefield_supported_p (const aarch64_feature_set, const aarch64_sys_reg *); diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c index 7eee365..7e088a9 100644 --- a/opcodes/aarch64-dis.c +++ b/opcodes/aarch64-dis.c @@ -302,6 +302,7 @@ aarch64_ext_regno_pair (const aarch64_operand *self ATTRIBUTE_UNUSED, aarch64_op aarch64_operand_error *errors ATTRIBUTE_UNUSED) { assert (info->idx == 1 + || info->idx == 2 || info->idx == 3 || info->idx == 5); diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c index 70232f6..2e7472a 100644 --- a/opcodes/aarch64-opc.c +++ b/opcodes/aarch64-opc.c @@ -1710,7 +1710,7 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx, else if (type == AARCH64_OPND_PAIRREG || type == AARCH64_OPND_PAIRREG_OR_XZR) { - assert (idx == 1 || idx == 3 || idx == 5); + assert (idx == 1 || idx == 2 || idx == 3 || idx == 5); if (opnds[idx - 1].reg.regno % 2 != 0) { set_syntax_error (mismatch_detail, idx - 1, @@ -4514,6 +4514,7 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc, break; case AARCH64_OPND_SYSREG: + case AARCH64_OPND_SYSREG128: for (i = 0; aarch64_sys_regs[i].name; ++i) { const aarch64_sys_reg *sr = aarch64_sys_regs + i; @@ -4724,6 +4725,12 @@ aarch64_sys_reg_deprecated_p (const uint32_t reg_flags) } bool +aarch64_sys_reg_128bit_p (const uint32_t reg_flags) +{ + return (reg_flags & F_REG_128) != 0; +} + +bool aarch64_sys_reg_alias_p (const uint32_t reg_flags) { return (reg_flags & F_REG_ALIAS) != 0; diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h index bb8f343..288b3dd 100644 --- a/opcodes/aarch64-tbl.h +++ b/opcodes/aarch64-tbl.h @@ -4236,6 +4236,8 @@ const struct aarch64_opcode aarch64_opcode_table[] = CORE_INSN ("msr", 0xd5000000, 0xffe00000, ic_system, 0, OP2 (SYSREG, Rt), QL_SRC_X, F_SYS_WRITE), CORE_INSN ("sysl",0xd5280000, 0xfff80000, ic_system, 0, OP5 (Rt, UIMM3_OP1, CRn, CRm, UIMM3_OP2), QL_SYSL, 0), CORE_INSN ("mrs", 0xd5200000, 0xffe00000, ic_system, 0, OP2 (Rt, SYSREG), QL_DST_X, F_SYS_READ), + D128_INSN ("mrrs", 0xd5700000, 0xfff00000, OP3 (Rt, PAIRREG, SYSREG128), QL_DST_X2, F_SYS_READ), + D128_INSN ("msrr", 0xd5500000, 0xfff00000, OP3 (SYSREG128, Rt, PAIRREG), QL_SRC_X2, F_SYS_WRITE), CORE_INSN ("paciaz", 0xd503231f, 0xffffffff, ic_system, 0, OP0 (), {}, F_ALIAS), CORE_INSN ("paciasp", 0xd503233f, 0xffffffff, ic_system, 0, OP0 (), {}, F_ALIAS), CORE_INSN ("pacibz", 0xd503235f, 0xffffffff, ic_system, 0, OP0 (), {}, F_ALIAS), @@ -6342,6 +6344,7 @@ const struct aarch64_opcode aarch64_opcode_table[] = Y(ADDRESS, simd_addr_post, "SIMD_ADDR_POST", 0, F(), \ "a post-indexed address with immediate or register increment") \ Y(SYSTEM, sysreg, "SYSREG", 0, F(), "a system register") \ + Y(SYSTEM, sysreg, "SYSREG128", 0, F(), "a 128-bit system register") \ Y(SYSTEM, pstatefield, "PSTATEFIELD", 0, F(), \ "a PSTATE field name") \ Y(SYSTEM, sysins_op, "SYSREG_AT", 0, F(), \ -- 2.7.4