[v2] RISC-V: Add support for 'Zacas' atomic CAS

Message ID 1279cd5fe3d0b809a20e18ac61f817017cca7ec9.1697946848.git.research_trasio@irq.a4lg.com
State New
Headers
Series [v2] RISC-V: Add support for 'Zacas' atomic CAS |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_check--master-arm success Testing passed
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 success Testing passed

Commit Message

Tsukasa OI Oct. 22, 2023, 3:54 a.m. UTC
  From: Tsukasa OI <research_trasio@irq.a4lg.com>

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:
<https://github.com/riscv/riscv-zacas/releases/tag/v1.0-rc5>

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): 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      | 21 +++++++++++++++
 gas/testsuite/gas/riscv/zacas-64.s      | 13 +++++++++
 include/opcode/riscv-opc.h              | 11 ++++++++
 include/opcode/riscv.h                  |  1 +
 opcodes/riscv-opc.c                     | 36 +++++++++++++++++++++++++
 14 files changed, 156 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


base-commit: d249c8a63aec45648b2165532f79b09763870795
  

Comments

Tsukasa OI Oct. 22, 2023, 3:59 a.m. UTC | #1
Changes: v1 -> v2

1.  Added amocas.w* tests on RV64 (just because I forgot it)


That's it!

On 2023/10/22 12:54, Tsukasa OI wrote:
> From: Tsukasa OI <research_trasio@irq.a4lg.com>
> 
> 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:
> <https://github.com/riscv/riscv-zacas/releases/tag/v1.0-rc5>
> 
> 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): 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      | 21 +++++++++++++++
>  gas/testsuite/gas/riscv/zacas-64.s      | 13 +++++++++
>  include/opcode/riscv-opc.h              | 11 ++++++++
>  include/opcode/riscv.h                  |  1 +
>  opcodes/riscv-opc.c                     | 36 +++++++++++++++++++++++++
>  14 files changed, 156 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 c070394a3667..b7e067794ba8 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 000000000000..12c1bd90ac86
> --- /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 000000000000..944a66ba7806
> --- /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 a0,a5,\(a3\)'
> +.*: Error: illegal operands `amocas\.d\.aq a1,a4,\(a3\)'
> +.*: Error: illegal operands `amocas\.d\.aq a0,a5,\(a3\)'
> +.*: Error: illegal operands `amocas\.d\.rl a1,a4,\(a3\)'
> +.*: Error: illegal operands `amocas\.d\.rl a0,a5,\(a3\)'
> +.*: Error: illegal operands `amocas\.d\.aqrl a1,a4,\(a3\)'
> +.*: Error: illegal operands `amocas\.d\.aqrl a0,a5,\(a3\)'
> 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 000000000000..650ea1d8b6f2
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/zacas-32-fail.s
> @@ -0,0 +1,10 @@
> +target:
> +	# amocas.d (RV32): rd (operand 1) and rs2 (operand 2) must be even.
> +	amocas.d	a1, a4, (a3)
> +	amocas.d	a0, a5, (a3)
> +	amocas.d.aq	a1, a4, (a3)
> +	amocas.d.aq	a0, a5, (a3)
> +	amocas.d.rl	a1, a4, (a3)
> +	amocas.d.rl	a0, a5, (a3)
> +	amocas.d.aqrl	a1, a4, (a3)
> +	amocas.d.aqrl	a0, a5, (a3)
> diff --git a/gas/testsuite/gas/riscv/zacas-32.d b/gas/testsuite/gas/riscv/zacas-32.d
> new file mode 100644
> index 000000000000..60f4fe09f866
> --- /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 <target>:
> +[ 	]+[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]+:[ 	]+28e6b52f[ 	]+amocas\.d[ 		]+a0,a4,\(a3\)
> +[ 	]+[0-9a-f]+:[ 	]+2ce6b52f[ 	]+amocas\.d\.aq[ 	]+a0,a4,\(a3\)
> +[ 	]+[0-9a-f]+:[ 	]+2ae6b52f[ 	]+amocas\.d\.rl[ 	]+a0,a4,\(a3\)
> +[ 	]+[0-9a-f]+:[ 	]+2ee6b52f[ 	]+amocas\.d\.aqrl[ 	]+a0,a4,\(a3\)
> diff --git a/gas/testsuite/gas/riscv/zacas-32.s b/gas/testsuite/gas/riscv/zacas-32.s
> new file mode 100644
> index 000000000000..c12c0e42f338
> --- /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	a0, a4, (a3)
> +	amocas.d.aq	a0, a4, (a3)
> +	amocas.d.rl	a0, a4, (a3)
> +	amocas.d.aqrl	a0, a4, (a3)
> 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 000000000000..e1910d81f9e2
> --- /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 000000000000..74495401e153
> --- /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 a0,a5,\(a3\)'
> +.*: Error: illegal operands `amocas\.q\.aq a1,a4,\(a3\)'
> +.*: Error: illegal operands `amocas\.q\.aq a0,a5,\(a3\)'
> +.*: Error: illegal operands `amocas\.q\.rl a1,a4,\(a3\)'
> +.*: Error: illegal operands `amocas\.q\.rl a0,a5,\(a3\)'
> +.*: Error: illegal operands `amocas\.q\.aqrl a1,a4,\(a3\)'
> +.*: Error: illegal operands `amocas\.q\.aqrl a0,a5,\(a3\)'
> 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 000000000000..96ee4a378bf5
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/zacas-64-fail.s
> @@ -0,0 +1,10 @@
> +target:
> +	# amocas.q (RV64): rd (operand 1) and rs2 (operand 2) must be even.
> +	amocas.q	a1, a4, (a3)
> +	amocas.q	a0, a5, (a3)
> +	amocas.q.aq	a1, a4, (a3)
> +	amocas.q.aq	a0, a5, (a3)
> +	amocas.q.rl	a1, a4, (a3)
> +	amocas.q.rl	a0, a5, (a3)
> +	amocas.q.aqrl	a1, a4, (a3)
> +	amocas.q.aqrl	a0, a5, (a3)
> diff --git a/gas/testsuite/gas/riscv/zacas-64.d b/gas/testsuite/gas/riscv/zacas-64.d
> new file mode 100644
> index 000000000000..027806aad4fc
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/zacas-64.d
> @@ -0,0 +1,21 @@
> +#as: -march=rv64i_zacas
> +#objdump: -d
> +
> +.*:[ 	]+file format .*
> +
> +
> +Disassembly of section .text:
> +
> +0+000 <target>:
> +[ 	]+[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]+:[ 	]+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]+:[ 	]+28e6c52f[ 	]+amocas\.q[ 		]+a0,a4,\(a3\)
> +[ 	]+[0-9a-f]+:[ 	]+2ce6c52f[ 	]+amocas\.q\.aq[ 	]+a0,a4,\(a3\)
> +[ 	]+[0-9a-f]+:[ 	]+2ae6c52f[ 	]+amocas\.q\.rl[ 	]+a0,a4,\(a3\)
> +[ 	]+[0-9a-f]+:[ 	]+2ee6c52f[ 	]+amocas\.q\.aqrl[ 	]+a0,a4,\(a3\)
> diff --git a/gas/testsuite/gas/riscv/zacas-64.s b/gas/testsuite/gas/riscv/zacas-64.s
> new file mode 100644
> index 000000000000..3b9f7a0bfc7e
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/zacas-64.s
> @@ -0,0 +1,13 @@
> +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, a5, (a3)
> +	amocas.d.aq	a1, a5, (a3)
> +	amocas.d.rl	a1, a5, (a3)
> +	amocas.d.aqrl	a1, a5, (a3)
> +	amocas.q	a0, a4, (a3)
> +	amocas.q.aq	a0, a4, (a3)
> +	amocas.q.rl	a0, a4, (a3)
> +	amocas.q.aqrl	a0, a4, (a3)
> diff --git a/include/opcode/riscv-opc.h b/include/opcode/riscv-opc.h
> index 375483500e2a..8fb59e3db93e 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 93dd5169ebce..aefbfc7db81e 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 8e0ae85eb064..58087ca19cac 100644
> --- a/opcodes/riscv-opc.c
> +++ b/opcodes/riscv-opc.c
> @@ -290,6 +290,24 @@ 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 DEFINE_MATCH_FUNC_R(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 % G_RD == 0) \
> +	   && (rs1 % G_RS1 == 0) \
> +	   && (rs2 % G_RS2 == 0); \
> +  }
> +DEFINE_MATCH_FUNC_R(1, 1, 1)
> +DEFINE_MATCH_FUNC_R(2, 1, 2)
> +
>  static int
>  match_th_load_inc(const struct riscv_opcode *op,
>  		  insn_t insn)
> @@ -982,6 +1000,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_2_1_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_2_1_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_2_1_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_2_1_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_2_1_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_2_1_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_2_1_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_2_1_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 },
> 
> base-commit: d249c8a63aec45648b2165532f79b09763870795
  
Jan Beulich Oct. 23, 2023, 6:47 a.m. UTC | #2
On 22.10.2023 05:54, Tsukasa OI wrote:
> From: Tsukasa OI <research_trasio@irq.a4lg.com>
> 
> 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:
> <https://github.com/riscv/riscv-zacas/releases/tag/v1.0-rc5>
> 
> 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): 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      | 21 +++++++++++++++
>  gas/testsuite/gas/riscv/zacas-64.s      | 13 +++++++++
>  include/opcode/riscv-opc.h              | 11 ++++++++
>  include/opcode/riscv.h                  |  1 +
>  opcodes/riscv-opc.c                     | 36 +++++++++++++++++++++++++
>  14 files changed, 156 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 c070394a3667..b7e067794ba8 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 000000000000..12c1bd90ac86
> --- /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 000000000000..944a66ba7806
> --- /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 a0,a5,\(a3\)'
> +.*: Error: illegal operands `amocas\.d\.aq a1,a4,\(a3\)'
> +.*: Error: illegal operands `amocas\.d\.aq a0,a5,\(a3\)'
> +.*: Error: illegal operands `amocas\.d\.rl a1,a4,\(a3\)'
> +.*: Error: illegal operands `amocas\.d\.rl a0,a5,\(a3\)'
> +.*: Error: illegal operands `amocas\.d\.aqrl a1,a4,\(a3\)'
> +.*: Error: illegal operands `amocas\.d\.aqrl a0,a5,\(a3\)'
> 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 000000000000..650ea1d8b6f2
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/zacas-32-fail.s
> @@ -0,0 +1,10 @@
> +target:
> +	# amocas.d (RV32): rd (operand 1) and rs2 (operand 2) must be even.
> +	amocas.d	a1, a4, (a3)
> +	amocas.d	a0, a5, (a3)
> +	amocas.d.aq	a1, a4, (a3)
> +	amocas.d.aq	a0, a5, (a3)
> +	amocas.d.rl	a1, a4, (a3)
> +	amocas.d.rl	a0, a5, (a3)
> +	amocas.d.aqrl	a1, a4, (a3)
> +	amocas.d.aqrl	a0, a5, (a3)
> diff --git a/gas/testsuite/gas/riscv/zacas-32.d b/gas/testsuite/gas/riscv/zacas-32.d
> new file mode 100644
> index 000000000000..60f4fe09f866
> --- /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 <target>:
> +[ 	]+[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]+:[ 	]+28e6b52f[ 	]+amocas\.d[ 		]+a0,a4,\(a3\)
> +[ 	]+[0-9a-f]+:[ 	]+2ce6b52f[ 	]+amocas\.d\.aq[ 	]+a0,a4,\(a3\)
> +[ 	]+[0-9a-f]+:[ 	]+2ae6b52f[ 	]+amocas\.d\.rl[ 	]+a0,a4,\(a3\)
> +[ 	]+[0-9a-f]+:[ 	]+2ee6b52f[ 	]+amocas\.d\.aqrl[ 	]+a0,a4,\(a3\)
> diff --git a/gas/testsuite/gas/riscv/zacas-32.s b/gas/testsuite/gas/riscv/zacas-32.s
> new file mode 100644
> index 000000000000..c12c0e42f338
> --- /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	a0, a4, (a3)
> +	amocas.d.aq	a0, a4, (a3)
> +	amocas.d.rl	a0, a4, (a3)
> +	amocas.d.aqrl	a0, a4, (a3)
> 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 000000000000..e1910d81f9e2
> --- /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 000000000000..74495401e153
> --- /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 a0,a5,\(a3\)'
> +.*: Error: illegal operands `amocas\.q\.aq a1,a4,\(a3\)'
> +.*: Error: illegal operands `amocas\.q\.aq a0,a5,\(a3\)'
> +.*: Error: illegal operands `amocas\.q\.rl a1,a4,\(a3\)'
> +.*: Error: illegal operands `amocas\.q\.rl a0,a5,\(a3\)'
> +.*: Error: illegal operands `amocas\.q\.aqrl a1,a4,\(a3\)'
> +.*: Error: illegal operands `amocas\.q\.aqrl a0,a5,\(a3\)'
> 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 000000000000..96ee4a378bf5
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/zacas-64-fail.s
> @@ -0,0 +1,10 @@
> +target:
> +	# amocas.q (RV64): rd (operand 1) and rs2 (operand 2) must be even.
> +	amocas.q	a1, a4, (a3)
> +	amocas.q	a0, a5, (a3)
> +	amocas.q.aq	a1, a4, (a3)
> +	amocas.q.aq	a0, a5, (a3)
> +	amocas.q.rl	a1, a4, (a3)
> +	amocas.q.rl	a0, a5, (a3)
> +	amocas.q.aqrl	a1, a4, (a3)
> +	amocas.q.aqrl	a0, a5, (a3)
> diff --git a/gas/testsuite/gas/riscv/zacas-64.d b/gas/testsuite/gas/riscv/zacas-64.d
> new file mode 100644
> index 000000000000..027806aad4fc
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/zacas-64.d
> @@ -0,0 +1,21 @@
> +#as: -march=rv64i_zacas
> +#objdump: -d
> +
> +.*:[ 	]+file format .*
> +
> +
> +Disassembly of section .text:
> +
> +0+000 <target>:
> +[ 	]+[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]+:[ 	]+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]+:[ 	]+28e6c52f[ 	]+amocas\.q[ 		]+a0,a4,\(a3\)
> +[ 	]+[0-9a-f]+:[ 	]+2ce6c52f[ 	]+amocas\.q\.aq[ 	]+a0,a4,\(a3\)
> +[ 	]+[0-9a-f]+:[ 	]+2ae6c52f[ 	]+amocas\.q\.rl[ 	]+a0,a4,\(a3\)
> +[ 	]+[0-9a-f]+:[ 	]+2ee6c52f[ 	]+amocas\.q\.aqrl[ 	]+a0,a4,\(a3\)
> diff --git a/gas/testsuite/gas/riscv/zacas-64.s b/gas/testsuite/gas/riscv/zacas-64.s
> new file mode 100644
> index 000000000000..3b9f7a0bfc7e
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/zacas-64.s
> @@ -0,0 +1,13 @@
> +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, a5, (a3)
> +	amocas.d.aq	a1, a5, (a3)
> +	amocas.d.rl	a1, a5, (a3)
> +	amocas.d.aqrl	a1, a5, (a3)
> +	amocas.q	a0, a4, (a3)
> +	amocas.q.aq	a0, a4, (a3)
> +	amocas.q.rl	a0, a4, (a3)
> +	amocas.q.aqrl	a0, a4, (a3)
> diff --git a/include/opcode/riscv-opc.h b/include/opcode/riscv-opc.h
> index 375483500e2a..8fb59e3db93e 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 93dd5169ebce..aefbfc7db81e 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 8e0ae85eb064..58087ca19cac 100644
> --- a/opcodes/riscv-opc.c
> +++ b/opcodes/riscv-opc.c
> @@ -290,6 +290,24 @@ 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 DEFINE_MATCH_FUNC_R(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 % G_RD == 0) \
> +	   && (rs1 % G_RS1 == 0) \
> +	   && (rs2 % G_RS2 == 0); \
> +  }
> +DEFINE_MATCH_FUNC_R(1, 1, 1)
> +DEFINE_MATCH_FUNC_R(2, 1, 2)

Mind me asking what good the former of the two really does? It's just
match_opcode() aiui, properly obfuscated.

Jan
  
Tsukasa OI Oct. 24, 2023, 4:07 a.m. UTC | #3
On 2023/10/23 15:47, Jan Beulich wrote:
> 
> Mind me asking what good the former of the two really does? It's just
> match_opcode() aiui, properly obfuscated.
> 
> Jan
> 

****Excuse me?****

As a single patch set, I think Gianluca's patch with a minor fix will
work perfectly.  But, the concept of register pairs / register groups
are not specific to 'Zacas', that's what I'm talking about and the
reason I think Gianluca's patch set's match function will not be a long
term solution (actually, I found Gianluca's patch set after I wrote
mine, but that wouldn't change my opinion).

So, let me list all register group-related constraints in existing and
upcoming extensions (except all ones; x is "not applicable" and can be
theoretically replaced to "1" but it's probably better to be named "x"
to indicate that the instruction does not use "x" operand as register):

Extension   |  RD | RS1 | RS2 | RS3
----------- | --- | --- | --- | ---
Zdinx       |   2 |   2 |   2 |   x
Zdinx       |   2 |   2 |   2 |   2
Zdinx       |   x |   2 |   2 |   x
Zdinx       |   1 |   2 |   x |   x
Zdinx       |   2 |   1 |   x |   x
Zdinx       |   2 |   2 |   x |   x
----------- | --- | --- | --- | ---
Zqinx       |   2 |   2 |   2 |   x
Zqinx       |   4 |   4 |   4 |   x
Zqinx       |   2 |   2 |   2 |   2
Zqinx       |   4 |   4 |   4 |   4
Zqinx       |   x |   2 |   2 |   x
Zqinx       |   x |   4 |   4 |   x
Zqinx       |   1 |   2 |   x |   x
Zqinx       |   1 |   4 |   x |   x
Zqinx       |   2 |   1 |   x |   x
Zqinx       |   2 |   2 |   x |   x
Zqinx       |   2 |   4 |   x |   x
Zqinx       |   4 |   1 |   x |   x
Zqinx       |   4 |   2 |   x |   x
Zqinx       |   4 |   4 |   x |   x
----------- | --- | --- | --- | ---
Zpsfoperand |   2 |   1 |   1 |   x
Zpsfoperand |   2 |   2 |   1 |   x
Zpsfoperand |   2 |   2 |   2 |   x
----------- | --- | --- | --- | ---
Zacas       |   2 |   1 |   2 |   x

Lots of similar constraints but different values.  Don't you think a
generator macro is the best solution for this kind of situation?

Tsukasa
  
Jan Beulich Oct. 24, 2023, 6:02 a.m. UTC | #4
On 24.10.2023 06:07, Tsukasa OI wrote:
> On 2023/10/23 15:47, Jan Beulich wrote:
>>
>> Mind me asking what good the former of the two really does? It's just
>> match_opcode() aiui, properly obfuscated.
>>
>> Jan
>>
> 
> ****Excuse me?****
> 
> As a single patch set, I think Gianluca's patch with a minor fix will
> work perfectly.  But, the concept of register pairs / register groups
> are not specific to 'Zacas', that's what I'm talking about and the
> reason I think Gianluca's patch set's match function will not be a long
> term solution (actually, I found Gianluca's patch set after I wrote
> mine, but that wouldn't change my opinion).
> 
> So, let me list all register group-related constraints in existing and
> upcoming extensions (except all ones; x is "not applicable" and can be
> theoretically replaced to "1" but it's probably better to be named "x"
> to indicate that the instruction does not use "x" operand as register):
> 
> Extension   |  RD | RS1 | RS2 | RS3
> ----------- | --- | --- | --- | ---
> Zdinx       |   2 |   2 |   2 |   x
> Zdinx       |   2 |   2 |   2 |   2
> Zdinx       |   x |   2 |   2 |   x
> Zdinx       |   1 |   2 |   x |   x
> Zdinx       |   2 |   1 |   x |   x
> Zdinx       |   2 |   2 |   x |   x
> ----------- | --- | --- | --- | ---
> Zqinx       |   2 |   2 |   2 |   x
> Zqinx       |   4 |   4 |   4 |   x
> Zqinx       |   2 |   2 |   2 |   2
> Zqinx       |   4 |   4 |   4 |   4
> Zqinx       |   x |   2 |   2 |   x
> Zqinx       |   x |   4 |   4 |   x
> Zqinx       |   1 |   2 |   x |   x
> Zqinx       |   1 |   4 |   x |   x
> Zqinx       |   2 |   1 |   x |   x
> Zqinx       |   2 |   2 |   x |   x
> Zqinx       |   2 |   4 |   x |   x
> Zqinx       |   4 |   1 |   x |   x
> Zqinx       |   4 |   2 |   x |   x
> Zqinx       |   4 |   4 |   x |   x
> ----------- | --- | --- | --- | ---
> Zpsfoperand |   2 |   1 |   1 |   x
> Zpsfoperand |   2 |   2 |   1 |   x
> Zpsfoperand |   2 |   2 |   2 |   x
> ----------- | --- | --- | --- | ---
> Zacas       |   2 |   1 |   2 |   x
> 
> Lots of similar constraints but different values.  Don't you think a
> generator macro is the best solution for this kind of situation?

Certainly, and I didn't put the macro under question. "The former of the
two" was referring to the invocation of the macro with all 1 arguments.
Interestingly this case also doesn't appear in the table above (for,
perhaps, the very reason I was asking the question).

Jan
  
Nelson Chu Oct. 25, 2023, 2:15 a.m. UTC | #5
On Tue, Oct 24, 2023 at 2:03 PM Jan Beulich <jbeulich@suse.com> wrote:

> On 24.10.2023 06:07, Tsukasa OI wrote:
> > As a single patch set, I think Gianluca's patch with a minor fix will
> > work perfectly.  But, the concept of register pairs / register groups
> > are not specific to 'Zacas', that's what I'm talking about and the
> > reason I think Gianluca's patch set's match function will not be a long
> > term solution (actually, I found Gianluca's patch set after I wrote
> > mine, but that wouldn't change my opinion).
>

As I said before, I don't know if we really need the constraint checks for
register groups in assembler or not.  Or on the other hand, I don't know if
we really need the detailed register constraint checks for assembly
syntax.  I remembered you completely unacceptable to fight back that you
don't care about hardware testing since you were doing toolchain, but for
those DV guys, they are also one of the users of toolchain.  However, for
many things, lots of users are used to using some behaviors or code in the
toolchain.  These behaviors are not wrong, maybe they are just not that
rigorous.  Even though your idea may be beneficial to some people, it can
also cause problems for others.

So, I was not rejecting your idea before, I was just trying to let you know
every change you made may cause trouble for others, especially that some
behaviors are established for many years.  Since the rvv register group
checks were argued before and removed, I will suggest we just
remove the same checks for zacas.  If other maintainers support that we
should also do these kinds of complicated constraint checks, then you can
ignore my comments.

Thanks
Nelson
  
Jan Beulich Oct. 25, 2023, 6:02 a.m. UTC | #6
On 25.10.2023 04:15, Nelson Chu wrote:
> On Tue, Oct 24, 2023 at 2:03 PM Jan Beulich <jbeulich@suse.com> wrote:
> 
>> On 24.10.2023 06:07, Tsukasa OI wrote:
>>> As a single patch set, I think Gianluca's patch with a minor fix will
>>> work perfectly.  But, the concept of register pairs / register groups
>>> are not specific to 'Zacas', that's what I'm talking about and the
>>> reason I think Gianluca's patch set's match function will not be a long
>>> term solution (actually, I found Gianluca's patch set after I wrote
>>> mine, but that wouldn't change my opinion).
>>
> 
> As I said before, I don't know if we really need the constraint checks for
> register groups in assembler or not.  Or on the other hand, I don't know if
> we really need the detailed register constraint checks for assembly
> syntax.  I remembered you completely unacceptable to fight back that you
> don't care about hardware testing since you were doing toolchain, but for
> those DV guys, they are also one of the users of toolchain.  However, for
> many things, lots of users are used to using some behaviors or code in the
> toolchain.  These behaviors are not wrong, maybe they are just not that
> rigorous.  Even though your idea may be beneficial to some people, it can
> also cause problems for others.
> 
> So, I was not rejecting your idea before, I was just trying to let you know
> every change you made may cause trouble for others, especially that some
> behaviors are established for many years.  Since the rvv register group
> checks were argued before and removed, I will suggest we just
> remove the same checks for zacas.  If other maintainers support that we
> should also do these kinds of complicated constraint checks, then you can
> ignore my comments.

First, despite being sent To: me, I assume your reply was targeted at
Tsukasa?

Irrespective, while I'm not a RISC-V maintainer, I'd like to advocate in
favor of these checks (uniformly wherever applicable). If they pose
problems to certain people, let's have a command line option to suppress
them. (To some degree these checks are related to a remark towards hint
insns that I had raised quite some time ago: When doing things really
strictly, I continue to be of the opinion that those should only ever be
expressed as "hint", with their non-hint forms - e.g. some kind of ALU
insn with x0 as destination - at least warned about. The main issue
there obviously is how to pick among the many hint forms with just a
single "hint" mnemonic.)

Jan
  

Patch

diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index c070394a3667..b7e067794ba8 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 000000000000..12c1bd90ac86
--- /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 000000000000..944a66ba7806
--- /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 a0,a5,\(a3\)'
+.*: Error: illegal operands `amocas\.d\.aq a1,a4,\(a3\)'
+.*: Error: illegal operands `amocas\.d\.aq a0,a5,\(a3\)'
+.*: Error: illegal operands `amocas\.d\.rl a1,a4,\(a3\)'
+.*: Error: illegal operands `amocas\.d\.rl a0,a5,\(a3\)'
+.*: Error: illegal operands `amocas\.d\.aqrl a1,a4,\(a3\)'
+.*: Error: illegal operands `amocas\.d\.aqrl a0,a5,\(a3\)'
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 000000000000..650ea1d8b6f2
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zacas-32-fail.s
@@ -0,0 +1,10 @@ 
+target:
+	# amocas.d (RV32): rd (operand 1) and rs2 (operand 2) must be even.
+	amocas.d	a1, a4, (a3)
+	amocas.d	a0, a5, (a3)
+	amocas.d.aq	a1, a4, (a3)
+	amocas.d.aq	a0, a5, (a3)
+	amocas.d.rl	a1, a4, (a3)
+	amocas.d.rl	a0, a5, (a3)
+	amocas.d.aqrl	a1, a4, (a3)
+	amocas.d.aqrl	a0, a5, (a3)
diff --git a/gas/testsuite/gas/riscv/zacas-32.d b/gas/testsuite/gas/riscv/zacas-32.d
new file mode 100644
index 000000000000..60f4fe09f866
--- /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 <target>:
+[ 	]+[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]+:[ 	]+28e6b52f[ 	]+amocas\.d[ 		]+a0,a4,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+2ce6b52f[ 	]+amocas\.d\.aq[ 	]+a0,a4,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+2ae6b52f[ 	]+amocas\.d\.rl[ 	]+a0,a4,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+2ee6b52f[ 	]+amocas\.d\.aqrl[ 	]+a0,a4,\(a3\)
diff --git a/gas/testsuite/gas/riscv/zacas-32.s b/gas/testsuite/gas/riscv/zacas-32.s
new file mode 100644
index 000000000000..c12c0e42f338
--- /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	a0, a4, (a3)
+	amocas.d.aq	a0, a4, (a3)
+	amocas.d.rl	a0, a4, (a3)
+	amocas.d.aqrl	a0, a4, (a3)
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 000000000000..e1910d81f9e2
--- /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 000000000000..74495401e153
--- /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 a0,a5,\(a3\)'
+.*: Error: illegal operands `amocas\.q\.aq a1,a4,\(a3\)'
+.*: Error: illegal operands `amocas\.q\.aq a0,a5,\(a3\)'
+.*: Error: illegal operands `amocas\.q\.rl a1,a4,\(a3\)'
+.*: Error: illegal operands `amocas\.q\.rl a0,a5,\(a3\)'
+.*: Error: illegal operands `amocas\.q\.aqrl a1,a4,\(a3\)'
+.*: Error: illegal operands `amocas\.q\.aqrl a0,a5,\(a3\)'
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 000000000000..96ee4a378bf5
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zacas-64-fail.s
@@ -0,0 +1,10 @@ 
+target:
+	# amocas.q (RV64): rd (operand 1) and rs2 (operand 2) must be even.
+	amocas.q	a1, a4, (a3)
+	amocas.q	a0, a5, (a3)
+	amocas.q.aq	a1, a4, (a3)
+	amocas.q.aq	a0, a5, (a3)
+	amocas.q.rl	a1, a4, (a3)
+	amocas.q.rl	a0, a5, (a3)
+	amocas.q.aqrl	a1, a4, (a3)
+	amocas.q.aqrl	a0, a5, (a3)
diff --git a/gas/testsuite/gas/riscv/zacas-64.d b/gas/testsuite/gas/riscv/zacas-64.d
new file mode 100644
index 000000000000..027806aad4fc
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zacas-64.d
@@ -0,0 +1,21 @@ 
+#as: -march=rv64i_zacas
+#objdump: -d
+
+.*:[ 	]+file format .*
+
+
+Disassembly of section .text:
+
+0+000 <target>:
+[ 	]+[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]+:[ 	]+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]+:[ 	]+28e6c52f[ 	]+amocas\.q[ 		]+a0,a4,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+2ce6c52f[ 	]+amocas\.q\.aq[ 	]+a0,a4,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+2ae6c52f[ 	]+amocas\.q\.rl[ 	]+a0,a4,\(a3\)
+[ 	]+[0-9a-f]+:[ 	]+2ee6c52f[ 	]+amocas\.q\.aqrl[ 	]+a0,a4,\(a3\)
diff --git a/gas/testsuite/gas/riscv/zacas-64.s b/gas/testsuite/gas/riscv/zacas-64.s
new file mode 100644
index 000000000000..3b9f7a0bfc7e
--- /dev/null
+++ b/gas/testsuite/gas/riscv/zacas-64.s
@@ -0,0 +1,13 @@ 
+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, a5, (a3)
+	amocas.d.aq	a1, a5, (a3)
+	amocas.d.rl	a1, a5, (a3)
+	amocas.d.aqrl	a1, a5, (a3)
+	amocas.q	a0, a4, (a3)
+	amocas.q.aq	a0, a4, (a3)
+	amocas.q.rl	a0, a4, (a3)
+	amocas.q.aqrl	a0, a4, (a3)
diff --git a/include/opcode/riscv-opc.h b/include/opcode/riscv-opc.h
index 375483500e2a..8fb59e3db93e 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 93dd5169ebce..aefbfc7db81e 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 8e0ae85eb064..58087ca19cac 100644
--- a/opcodes/riscv-opc.c
+++ b/opcodes/riscv-opc.c
@@ -290,6 +290,24 @@  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 DEFINE_MATCH_FUNC_R(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 % G_RD == 0) \
+	   && (rs1 % G_RS1 == 0) \
+	   && (rs2 % G_RS2 == 0); \
+  }
+DEFINE_MATCH_FUNC_R(1, 1, 1)
+DEFINE_MATCH_FUNC_R(2, 1, 2)
+
 static int
 match_th_load_inc(const struct riscv_opcode *op,
 		  insn_t insn)
@@ -982,6 +1000,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_2_1_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_2_1_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_2_1_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_2_1_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_2_1_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_2_1_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_2_1_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_2_1_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 },