From c6ab6d2b98a2f8588b932b2e6acaf7f6bacdba52 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Tue, 17 Oct 2023 02:09:17 +0000 Subject: [PATCH] RISC-V: Add support for 'Zacas' atomic CAS This commit adds support for the 'Zacas' extension, adding atomic CAS instructions. Beware that this extension also introduces the concept of register pairs and it checks the validity of rs1 and rs2 if applicable. This is based on the latest (frozen) draft: bfd/ChangeLog: * elfxx-riscv.c (riscv_implicit_subsets): Make 'Zacas' to imply 'A' extension. (riscv_supported_std_z_ext): Add 'Zacas' to the supported list. (riscv_multi_subset_supports, riscv_multi_subset_supports_ext): Add handling for new instruction class. gas/ChangeLog: * testsuite/gas/riscv/zacas-32.s: New test. * testsuite/gas/riscv/zacas-32.d: Likewise. * testsuite/gas/riscv/zacas-64.s: Likewise. * testsuite/gas/riscv/zacas-64.d: Likewise. * testsuite/gas/riscv/zacas-32-fail.s: New failure test. * testsuite/gas/riscv/zacas-32-fail.d: Likewise. * testsuite/gas/riscv/zacas-32-fail.l: Likewise. * testsuite/gas/riscv/zacas-64-fail.s: New failure test. * testsuite/gas/riscv/zacas-64-fail.d: Likewise. * testsuite/gas/riscv/zacas-64-fail.l: Likewise. include/ChangeLog: * opcode/riscv-opc.h (MATCH_AMOCAS_D, MASK_AMOCAS_D, MATCH_AMOCAS_Q, MASK_AMOCAS_Q, MATCH_AMOCAS_W, MASK_AMOCAS_W): New. * opcode/riscv.h (enum riscv_insn_class): Add new instruction class INSN_CLASS_ZACAS. opcodes/ChangeLog: * riscv-opc.c (REGGROUP_REGS_x, REGGROUP_REGS_1, REGGROUP_REGS_2, DEFINE_MATCH_FUNC_R_3): New match function template with register groups. (match_reggroup_r_1_1_1, match_reggroup_r_1_2_2): New. (riscv_opcodes): Add atomic CAS instructions. --- bfd/elfxx-riscv.c | 6 ++++ gas/testsuite/gas/riscv/zacas-32-fail.d | 2 ++ gas/testsuite/gas/riscv/zacas-32-fail.l | 9 ++++++ gas/testsuite/gas/riscv/zacas-32-fail.s | 10 +++++++ gas/testsuite/gas/riscv/zacas-32.d | 17 +++++++++++ gas/testsuite/gas/riscv/zacas-32.s | 9 ++++++ gas/testsuite/gas/riscv/zacas-64-fail.d | 2 ++ gas/testsuite/gas/riscv/zacas-64-fail.l | 9 ++++++ gas/testsuite/gas/riscv/zacas-64-fail.s | 10 +++++++ gas/testsuite/gas/riscv/zacas-64.d | 17 +++++++++++ gas/testsuite/gas/riscv/zacas-64.s | 9 ++++++ include/opcode/riscv-opc.h | 11 +++++++ include/opcode/riscv.h | 1 + opcodes/riscv-opc.c | 40 +++++++++++++++++++++++++ 14 files changed, 152 insertions(+) create mode 100644 gas/testsuite/gas/riscv/zacas-32-fail.d create mode 100644 gas/testsuite/gas/riscv/zacas-32-fail.l create mode 100644 gas/testsuite/gas/riscv/zacas-32-fail.s create mode 100644 gas/testsuite/gas/riscv/zacas-32.d create mode 100644 gas/testsuite/gas/riscv/zacas-32.s create mode 100644 gas/testsuite/gas/riscv/zacas-64-fail.d create mode 100644 gas/testsuite/gas/riscv/zacas-64-fail.l create mode 100644 gas/testsuite/gas/riscv/zacas-64-fail.s create mode 100644 gas/testsuite/gas/riscv/zacas-64.d create mode 100644 gas/testsuite/gas/riscv/zacas-64.s diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c index c070394a366..b7e067794ba 100644 --- a/bfd/elfxx-riscv.c +++ b/bfd/elfxx-riscv.c @@ -1148,6 +1148,7 @@ static struct riscv_implicit_subset riscv_implicit_subsets[] = {"zhinx", "zhinxmin", check_implicit_always}, {"zhinxmin", "zfinx", check_implicit_always}, {"zfinx", "zicsr", check_implicit_always}, + {"zacas", "a", check_implicit_always}, {"zk", "zkn", check_implicit_always}, {"zk", "zkr", check_implicit_always}, {"zk", "zkt", check_implicit_always}, @@ -1259,6 +1260,7 @@ static struct riscv_supported_ext riscv_supported_std_z_ext[] = {"zihintntl", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {"zihintpause", ISA_SPEC_CLASS_DRAFT, 2, 0, 0 }, {"zmmul", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, + {"zacas", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {"zawrs", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, {"zfa", ISA_SPEC_CLASS_DRAFT, 0, 1, 0 }, {"zfh", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 }, @@ -2409,6 +2411,8 @@ riscv_multi_subset_supports (riscv_parse_subset_t *rps, return riscv_subset_supports (rps, "zmmul"); case INSN_CLASS_A: return riscv_subset_supports (rps, "a"); + case INSN_CLASS_ZACAS: + return riscv_subset_supports (rps, "zacas"); case INSN_CLASS_ZAWRS: return riscv_subset_supports (rps, "zawrs"); case INSN_CLASS_F: @@ -2619,6 +2623,8 @@ riscv_multi_subset_supports_ext (riscv_parse_subset_t *rps, return _ ("m' or `zmmul"); case INSN_CLASS_A: return "a"; + case INSN_CLASS_ZACAS: + return "zacas"; case INSN_CLASS_ZAWRS: return "zawrs"; case INSN_CLASS_F: diff --git a/gas/testsuite/gas/riscv/zacas-32-fail.d b/gas/testsuite/gas/riscv/zacas-32-fail.d new file mode 100644 index 00000000000..12c1bd90ac8 --- /dev/null +++ b/gas/testsuite/gas/riscv/zacas-32-fail.d @@ -0,0 +1,2 @@ +#as: -march=rv32i_zacas +#error_output: zacas-32-fail.l diff --git a/gas/testsuite/gas/riscv/zacas-32-fail.l b/gas/testsuite/gas/riscv/zacas-32-fail.l new file mode 100644 index 00000000000..ecfb79d1306 --- /dev/null +++ b/gas/testsuite/gas/riscv/zacas-32-fail.l @@ -0,0 +1,9 @@ +.*: Assembler messages: +.*: Error: illegal operands `amocas\.d a1,a4,\(a3\)' +.*: Error: illegal operands `amocas\.d a1,a5,\(a2\)' +.*: Error: illegal operands `amocas\.d\.aq a1,a4,\(a3\)' +.*: Error: illegal operands `amocas\.d\.aq a1,a5,\(a2\)' +.*: Error: illegal operands `amocas\.d\.rl a1,a4,\(a3\)' +.*: Error: illegal operands `amocas\.d\.rl a1,a5,\(a2\)' +.*: Error: illegal operands `amocas\.d\.aqrl a1,a4,\(a3\)' +.*: Error: illegal operands `amocas\.d\.aqrl a1,a5,\(a2\)' diff --git a/gas/testsuite/gas/riscv/zacas-32-fail.s b/gas/testsuite/gas/riscv/zacas-32-fail.s new file mode 100644 index 00000000000..da7c6365858 --- /dev/null +++ b/gas/testsuite/gas/riscv/zacas-32-fail.s @@ -0,0 +1,10 @@ +target: + # amocas.d (RV32): rs1 (operand 3) and rs2 (operand 2) must be even. + amocas.d a1, a4, (a3) + amocas.d a1, a5, (a2) + amocas.d.aq a1, a4, (a3) + amocas.d.aq a1, a5, (a2) + amocas.d.rl a1, a4, (a3) + amocas.d.rl a1, a5, (a2) + amocas.d.aqrl a1, a4, (a3) + amocas.d.aqrl a1, a5, (a2) diff --git a/gas/testsuite/gas/riscv/zacas-32.d b/gas/testsuite/gas/riscv/zacas-32.d new file mode 100644 index 00000000000..e9f86b0d4e7 --- /dev/null +++ b/gas/testsuite/gas/riscv/zacas-32.d @@ -0,0 +1,17 @@ +#as: -march=rv32i_zacas +#objdump: -d + +.*:[ ]+file format .* + + +Disassembly of section .text: + +0+000 : +[ ]+[0-9a-f]+:[ ]+28f6a5af[ ]+amocas\.w[ ]+a1,a5,\(a3\) +[ ]+[0-9a-f]+:[ ]+2cf6a5af[ ]+amocas\.w\.aq[ ]+a1,a5,\(a3\) +[ ]+[0-9a-f]+:[ ]+2af6a5af[ ]+amocas\.w\.rl[ ]+a1,a5,\(a3\) +[ ]+[0-9a-f]+:[ ]+2ef6a5af[ ]+amocas\.w\.aqrl[ ]+a1,a5,\(a3\) +[ ]+[0-9a-f]+:[ ]+28e635af[ ]+amocas\.d[ ]+a1,a4,\(a2\) +[ ]+[0-9a-f]+:[ ]+2ce635af[ ]+amocas\.d\.aq[ ]+a1,a4,\(a2\) +[ ]+[0-9a-f]+:[ ]+2ae635af[ ]+amocas\.d\.rl[ ]+a1,a4,\(a2\) +[ ]+[0-9a-f]+:[ ]+2ee635af[ ]+amocas\.d\.aqrl[ ]+a1,a4,\(a2\) diff --git a/gas/testsuite/gas/riscv/zacas-32.s b/gas/testsuite/gas/riscv/zacas-32.s new file mode 100644 index 00000000000..1984ff9e6fa --- /dev/null +++ b/gas/testsuite/gas/riscv/zacas-32.s @@ -0,0 +1,9 @@ +target: + amocas.w a1, a5, (a3) + amocas.w.aq a1, a5, (a3) + amocas.w.rl a1, a5, (a3) + amocas.w.aqrl a1, a5, (a3) + amocas.d a1, a4, (a2) + amocas.d.aq a1, a4, (a2) + amocas.d.rl a1, a4, (a2) + amocas.d.aqrl a1, a4, (a2) diff --git a/gas/testsuite/gas/riscv/zacas-64-fail.d b/gas/testsuite/gas/riscv/zacas-64-fail.d new file mode 100644 index 00000000000..e1910d81f9e --- /dev/null +++ b/gas/testsuite/gas/riscv/zacas-64-fail.d @@ -0,0 +1,2 @@ +#as: -march=rv64i_zacas +#error_output: zacas-64-fail.l diff --git a/gas/testsuite/gas/riscv/zacas-64-fail.l b/gas/testsuite/gas/riscv/zacas-64-fail.l new file mode 100644 index 00000000000..e1e84347e76 --- /dev/null +++ b/gas/testsuite/gas/riscv/zacas-64-fail.l @@ -0,0 +1,9 @@ +.*: Assembler messages: +.*: Error: illegal operands `amocas\.q a1,a4,\(a3\)' +.*: Error: illegal operands `amocas\.q a1,a5,\(a2\)' +.*: Error: illegal operands `amocas\.q\.aq a1,a4,\(a3\)' +.*: Error: illegal operands `amocas\.q\.aq a1,a5,\(a2\)' +.*: Error: illegal operands `amocas\.q\.rl a1,a4,\(a3\)' +.*: Error: illegal operands `amocas\.q\.rl a1,a5,\(a2\)' +.*: Error: illegal operands `amocas\.q\.aqrl a1,a4,\(a3\)' +.*: Error: illegal operands `amocas\.q\.aqrl a1,a5,\(a2\)' diff --git a/gas/testsuite/gas/riscv/zacas-64-fail.s b/gas/testsuite/gas/riscv/zacas-64-fail.s new file mode 100644 index 00000000000..3236ed04199 --- /dev/null +++ b/gas/testsuite/gas/riscv/zacas-64-fail.s @@ -0,0 +1,10 @@ +target: + # amocas.q (RV64): rs1 (operand 3) and rs2 (operand 2) must be even. + amocas.q a1, a4, (a3) + amocas.q a1, a5, (a2) + amocas.q.aq a1, a4, (a3) + amocas.q.aq a1, a5, (a2) + amocas.q.rl a1, a4, (a3) + amocas.q.rl a1, a5, (a2) + amocas.q.aqrl a1, a4, (a3) + amocas.q.aqrl a1, a5, (a2) diff --git a/gas/testsuite/gas/riscv/zacas-64.d b/gas/testsuite/gas/riscv/zacas-64.d new file mode 100644 index 00000000000..c9eb723127b --- /dev/null +++ b/gas/testsuite/gas/riscv/zacas-64.d @@ -0,0 +1,17 @@ +#as: -march=rv64i_zacas +#objdump: -d + +.*:[ ]+file format .* + + +Disassembly of section .text: + +0+000 : +[ ]+[0-9a-f]+:[ ]+28f6b5af[ ]+amocas\.d[ ]+a1,a5,\(a3\) +[ ]+[0-9a-f]+:[ ]+2cf6b5af[ ]+amocas\.d\.aq[ ]+a1,a5,\(a3\) +[ ]+[0-9a-f]+:[ ]+2af6b5af[ ]+amocas\.d\.rl[ ]+a1,a5,\(a3\) +[ ]+[0-9a-f]+:[ ]+2ef6b5af[ ]+amocas\.d\.aqrl[ ]+a1,a5,\(a3\) +[ ]+[0-9a-f]+:[ ]+28e645af[ ]+amocas\.q[ ]+a1,a4,\(a2\) +[ ]+[0-9a-f]+:[ ]+2ce645af[ ]+amocas\.q\.aq[ ]+a1,a4,\(a2\) +[ ]+[0-9a-f]+:[ ]+2ae645af[ ]+amocas\.q\.rl[ ]+a1,a4,\(a2\) +[ ]+[0-9a-f]+:[ ]+2ee645af[ ]+amocas\.q\.aqrl[ ]+a1,a4,\(a2\) diff --git a/gas/testsuite/gas/riscv/zacas-64.s b/gas/testsuite/gas/riscv/zacas-64.s new file mode 100644 index 00000000000..b9004487a2e --- /dev/null +++ b/gas/testsuite/gas/riscv/zacas-64.s @@ -0,0 +1,9 @@ +target: + amocas.d a1, a5, (a3) + amocas.d.aq a1, a5, (a3) + amocas.d.rl a1, a5, (a3) + amocas.d.aqrl a1, a5, (a3) + amocas.q a1, a4, (a2) + amocas.q.aq a1, a4, (a2) + amocas.q.rl a1, a4, (a2) + amocas.q.aqrl a1, a4, (a2) diff --git a/include/opcode/riscv-opc.h b/include/opcode/riscv-opc.h index 375483500e2..8fb59e3db93 100644 --- a/include/opcode/riscv-opc.h +++ b/include/opcode/riscv-opc.h @@ -2315,6 +2315,13 @@ #define MASK_C_NTL_S1 0xffff #define MATCH_C_NTL_ALL 0x9016 #define MASK_C_NTL_ALL 0xffff +/* Zacas instructions. */ +#define MATCH_AMOCAS_D 0x2800302f +#define MASK_AMOCAS_D 0xf800707f +#define MATCH_AMOCAS_Q 0x2800402f +#define MASK_AMOCAS_Q 0xf800707f +#define MATCH_AMOCAS_W 0x2800202f +#define MASK_AMOCAS_W 0xf800707f /* Zawrs instructions. */ #define MATCH_WRS_NTO 0x00d00073 #define MASK_WRS_NTO 0xffffffff @@ -3370,6 +3377,10 @@ DECLARE_INSN(c_ntl_p1, MATCH_C_NTL_P1, MASK_C_NTL_P1) DECLARE_INSN(c_ntl_pall, MATCH_C_NTL_PALL, MASK_C_NTL_PALL) DECLARE_INSN(c_ntl_s1, MATCH_C_NTL_S1, MASK_C_NTL_S1) DECLARE_INSN(c_ntl_all, MATCH_C_NTL_ALL, MASK_C_NTL_ALL) +/* Zacas instructions. */ +DECLARE_INSN(amocas_d, MATCH_AMOCAS_D, MASK_AMOCAS_D) +DECLARE_INSN(amocas_q, MATCH_AMOCAS_Q, MASK_AMOCAS_Q) +DECLARE_INSN(amocas_w, MATCH_AMOCAS_W, MASK_AMOCAS_W) /* Zawrs instructions. */ DECLARE_INSN(wrs_nto, MATCH_WRS_NTO, MASK_WRS_NTO) DECLARE_INSN(wrs_sto, MATCH_WRS_STO, MASK_WRS_STO) diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h index 93dd5169ebc..aefbfc7db81 100644 --- a/include/opcode/riscv.h +++ b/include/opcode/riscv.h @@ -396,6 +396,7 @@ enum riscv_insn_class INSN_CLASS_ZIHINTNTL_AND_C, INSN_CLASS_ZIHINTPAUSE, INSN_CLASS_ZMMUL, + INSN_CLASS_ZACAS, INSN_CLASS_ZAWRS, INSN_CLASS_F_INX, INSN_CLASS_D_INX, diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c index 8e0ae85eb06..02e3f0ed482 100644 --- a/opcodes/riscv-opc.c +++ b/opcodes/riscv-opc.c @@ -290,6 +290,28 @@ match_vd_eq_vs1_eq_vs2 (const struct riscv_opcode *op, return match_opcode (op, insn) && vd == vs1 && vs1 == vs2; } +/* Instructions with register groups. */ + +#define REGGROUP_REGS_x 1 +#define REGGROUP_REGS_1 1 +#define REGGROUP_REGS_2 2 + +#define DEFINE_MATCH_FUNC_R_3(G_RD,G_RS1,G_RS2) \ + static int \ + match_reggroup_r_##G_RD##_##G_RS1##_##G_RS2 (const struct riscv_opcode *op, \ + insn_t insn) \ + { \ + int rd = (insn & MASK_RD) >> OP_SH_RD; \ + int rs1 = (insn & MASK_RS1) >> OP_SH_RS1; \ + int rs2 = (insn & MASK_RS2) >> OP_SH_RS2; \ + return match_opcode (op, insn) \ + && (rd % REGGROUP_REGS_##G_RD == 0) \ + && (rs1 % REGGROUP_REGS_##G_RS1 == 0) \ + && (rs2 % REGGROUP_REGS_##G_RS2 == 0); \ + } +DEFINE_MATCH_FUNC_R_3(1, 1, 1) +DEFINE_MATCH_FUNC_R_3(1, 2, 2) + static int match_th_load_inc(const struct riscv_opcode *op, insn_t insn) @@ -982,6 +1004,24 @@ const struct riscv_opcode riscv_opcodes[] = {"czero.eqz", 0, INSN_CLASS_ZICOND, "d,s,t", MATCH_CZERO_EQZ, MASK_CZERO_EQZ, match_opcode, 0 }, {"czero.nez", 0, INSN_CLASS_ZICOND, "d,s,t", MATCH_CZERO_NEZ, MASK_CZERO_NEZ, match_opcode, 0 }, +/* Zacas instructions. */ +{"amocas.w", 0, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_W, MASK_AMOCAS_W|MASK_AQRL, match_opcode, INSN_DREF|INSN_4_BYTE }, +{"amocas.w.aq", 0, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_W|MASK_AQ, MASK_AMOCAS_W|MASK_AQRL, match_opcode, INSN_DREF|INSN_4_BYTE }, +{"amocas.w.rl", 0, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_W|MASK_RL, MASK_AMOCAS_W|MASK_AQRL, match_opcode, INSN_DREF|INSN_4_BYTE }, +{"amocas.w.aqrl", 0, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_W|MASK_AQRL, MASK_AMOCAS_W|MASK_AQRL, match_opcode, INSN_DREF|INSN_4_BYTE }, +{"amocas.d", 32, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_D, MASK_AMOCAS_D|MASK_AQRL, match_reggroup_r_1_2_2, INSN_DREF|INSN_8_BYTE }, +{"amocas.d", 64, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_D, MASK_AMOCAS_D|MASK_AQRL, match_reggroup_r_1_1_1, INSN_DREF|INSN_8_BYTE }, +{"amocas.d.aq", 32, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_D|MASK_AQ, MASK_AMOCAS_D|MASK_AQRL, match_reggroup_r_1_2_2, INSN_DREF|INSN_8_BYTE }, +{"amocas.d.aq", 64, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_D|MASK_AQ, MASK_AMOCAS_D|MASK_AQRL, match_reggroup_r_1_1_1, INSN_DREF|INSN_8_BYTE }, +{"amocas.d.rl", 32, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_D|MASK_RL, MASK_AMOCAS_D|MASK_AQRL, match_reggroup_r_1_2_2, INSN_DREF|INSN_8_BYTE }, +{"amocas.d.rl", 64, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_D|MASK_RL, MASK_AMOCAS_D|MASK_AQRL, match_reggroup_r_1_1_1, INSN_DREF|INSN_8_BYTE }, +{"amocas.d.aqrl", 32, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_D|MASK_AQRL, MASK_AMOCAS_D|MASK_AQRL, match_reggroup_r_1_2_2, INSN_DREF|INSN_8_BYTE }, +{"amocas.d.aqrl", 64, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_D|MASK_AQRL, MASK_AMOCAS_D|MASK_AQRL, match_reggroup_r_1_1_1, INSN_DREF|INSN_8_BYTE }, +{"amocas.q", 64, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_Q, MASK_AMOCAS_Q|MASK_AQRL, match_reggroup_r_1_2_2, INSN_DREF|INSN_16_BYTE }, +{"amocas.q.aq", 64, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_Q|MASK_AQ, MASK_AMOCAS_Q|MASK_AQRL, match_reggroup_r_1_2_2, INSN_DREF|INSN_16_BYTE }, +{"amocas.q.rl", 64, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_Q|MASK_RL, MASK_AMOCAS_Q|MASK_AQRL, match_reggroup_r_1_2_2, INSN_DREF|INSN_16_BYTE }, +{"amocas.q.aqrl", 64, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_Q|MASK_AQRL, MASK_AMOCAS_Q|MASK_AQRL, match_reggroup_r_1_2_2, INSN_DREF|INSN_16_BYTE }, + /* Zawrs instructions. */ {"wrs.nto", 0, INSN_CLASS_ZAWRS, "", MATCH_WRS_NTO, MASK_WRS_NTO, match_opcode, 0 }, {"wrs.sto", 0, INSN_CLASS_ZAWRS, "", MATCH_WRS_STO, MASK_WRS_STO, match_opcode, 0 },