diff mbox series

[v2] RISC-V: Add basic support for the Zacas extension

Message ID 20240724001544.1359640-1-patrick@rivosinc.com
State New
Headers show
Series [v2] RISC-V: Add basic support for the Zacas extension | expand

Commit Message

Patrick O'Neill July 24, 2024, 12:15 a.m. UTC
From: Gianluca Guida <gianluca@rivosinc.com>

This patch adds support for amocas.{b|h|w|d}. Support for amocas.q
(64/128 bit cas for rv32/64) will be added in a future patch.

Extension: https://github.com/riscv/riscv-zacas
Ratification: https://jira.riscv.org/browse/RVS-680

gcc/ChangeLog:

	* common/config/riscv/riscv-common.cc
	(riscv_subset_list::to_string): Skip zacas when not supported by
	the assembler.
	* config.in: Regenerate.
	* config/riscv/arch-canonicalize: Make zacas imply zaamo.
	* config/riscv/riscv.opt: Add zacas.
	* config/riscv/sync.md (zacas_atomic_cas_value<mode>): New pattern.
	(atomic_compare_and_swap<mode>): Use new pattern for compare-and-swap ops.
	(zalrsc_atomic_cas_value_strong<mode>): Rename atomic_cas_value_strong.
	* configure: Regenerate.
	* configure.ac: Regenerate.
	* doc/sourcebuild.texi: Add Zacas documentation.

gcc/testsuite/ChangeLog:

	* lib/target-supports.exp: Add zacas testsuite infra support.
	* gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-acquire-release.c:
	Remove zacas to continue to test the lr/sc pairs.
	* gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-acquire.c: Ditto.
	* gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-consume.c: Ditto.
	* gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-relaxed.c: Ditto.
	* gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-release.c: Ditto.
	* gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-seq-cst-relaxed.c: Ditto.
	* gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-seq-cst.c: Ditto.
	* gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-acquire-release.c: Ditto.
	* gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-acquire.c: Ditto.
	* gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-consume.c: Ditto.
	* gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-relaxed.c: Ditto.
	* gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-release.c: Ditto.
	* gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-seq-cst-relaxed.c: Ditto.
	* gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-seq-cst.c: Ditto.
	* gcc.target/riscv/amo/zabha-zacas-preferred-over-zalrsc.c: New test.
	* gcc.target/riscv/amo/zacas-char-requires-zabha.c: New test.
	* gcc.target/riscv/amo/zacas-char-requires-zacas.c: New test.
	* gcc.target/riscv/amo/zacas-preferred-over-zalrsc.c: New test.
	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-acq-rel.c: New test.
	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-acquire.c: New test.
	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-relaxed.c: New test.
	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-release.c: New test.
	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-seq-cst.c: New test.
	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-compatability-mapping-no-fence.c:
	New test.
	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-compatability-mapping.cc: New test.
	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-acq-rel.c: New test.
	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-acquire.c: New test.
	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-relaxed.c: New test.
	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-release.c: New test.
	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-seq-cst.c: New test.
	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-acq-rel.c: New test.
	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-acquire.c: New test.
	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-relaxed.c: New test.
	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-release.c: New test.
	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-seq-cst.c: New test.
	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-char-seq-cst.c: New test.
	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-char.c: New test.
	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-compatability-mapping-no-fence.c:
	New test.
	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-compatability-mapping.cc: New test.
	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-int-seq-cst.c: New test.
	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-int.c: New test.
	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-short-seq-cst.c: New test.
	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-short.c: New test.

Co-authored-by: Patrick O'Neill <patrick@rivosinc.com>
---
V2 Changelog
* Fix functional bug where expected amocas value wasn't initialized.
* Add leading fence to zacas with seq_cst failure mode for PSABI
compatability (and corresponding testcases).
* Rename atomic_cas_value_strong to zalrsc_atomic_cas_value_strong.
* Remove unneeded zabha from int testcases.
* Add testcase functions that test weak compxchng.
* Add testcase for non-zabha zacas preferred over lrsc.

Tested locally with zaamo, zalrsc, ztso, and zacas with amo.exp.
---
 gcc/common/config/riscv/riscv-common.cc       |  11 ++
 gcc/config.in                                 |   6 +
 gcc/config/riscv/arch-canonicalize            |   1 +
 gcc/config/riscv/riscv.opt                    |   2 +
 gcc/config/riscv/sync.md                      | 109 ++++++++++++++++--
 gcc/configure                                 |  31 +++++
 gcc/configure.ac                              |   5 +
 gcc/doc/sourcebuild.texi                      |  10 ++
 .../amo/zabha-zacas-preferred-over-zalrsc.c   |  21 ++++
 .../riscv/amo/zacas-char-requires-zabha.c     |  17 +++
 .../riscv/amo/zacas-char-requires-zacas.c     |  17 +++
 .../riscv/amo/zacas-preferred-over-zalrsc.c   |  20 ++++
 ...acas-rvwmo-compare-exchange-char-acq-rel.c |  20 ++++
 ...acas-rvwmo-compare-exchange-char-acquire.c |  20 ++++
 ...acas-rvwmo-compare-exchange-char-relaxed.c |  20 ++++
 ...acas-rvwmo-compare-exchange-char-release.c |  20 ++++
 ...acas-rvwmo-compare-exchange-char-seq-cst.c |  20 ++++
 ...-exchange-compatability-mapping-no-fence.c |  30 +++++
 ...-compare-exchange-compatability-mapping.cc |  58 ++++++++++
 ...zacas-rvwmo-compare-exchange-int-acq-rel.c |  19 +++
 ...zacas-rvwmo-compare-exchange-int-acquire.c |  19 +++
 ...zacas-rvwmo-compare-exchange-int-relaxed.c |  19 +++
 ...zacas-rvwmo-compare-exchange-int-release.c |  19 +++
 ...zacas-rvwmo-compare-exchange-int-seq-cst.c |  19 +++
 ...cas-rvwmo-compare-exchange-short-acq-rel.c |  20 ++++
 ...cas-rvwmo-compare-exchange-short-acquire.c |  20 ++++
 ...cas-rvwmo-compare-exchange-short-relaxed.c |  20 ++++
 ...cas-rvwmo-compare-exchange-short-release.c |  20 ++++
 ...cas-rvwmo-compare-exchange-short-seq-cst.c |  20 ++++
 ...zacas-ztso-compare-exchange-char-seq-cst.c |  19 +++
 .../amo/zacas-ztso-compare-exchange-char.c    |  49 ++++++++
 ...-exchange-compatability-mapping-no-fence.c |  30 +++++
 ...-compare-exchange-compatability-mapping.cc |  58 ++++++++++
 .../zacas-ztso-compare-exchange-int-seq-cst.c |  18 +++
 .../amo/zacas-ztso-compare-exchange-int.c     |  48 ++++++++
 ...acas-ztso-compare-exchange-short-seq-cst.c |  19 +++
 .../amo/zacas-ztso-compare-exchange-short.c   |  49 ++++++++
 ...wmo-compare-exchange-int-acquire-release.c |   1 +
 ...alrsc-rvwmo-compare-exchange-int-acquire.c |   1 +
 ...alrsc-rvwmo-compare-exchange-int-consume.c |   1 +
 ...alrsc-rvwmo-compare-exchange-int-relaxed.c |   1 +
 ...alrsc-rvwmo-compare-exchange-int-release.c |   1 +
 ...wmo-compare-exchange-int-seq-cst-relaxed.c |   1 +
 ...alrsc-rvwmo-compare-exchange-int-seq-cst.c |   1 +
 ...tso-compare-exchange-int-acquire-release.c |   1 +
 ...zalrsc-ztso-compare-exchange-int-acquire.c |   1 +
 ...zalrsc-ztso-compare-exchange-int-consume.c |   1 +
 ...zalrsc-ztso-compare-exchange-int-relaxed.c |   1 +
 ...zalrsc-ztso-compare-exchange-int-release.c |   1 +
 ...tso-compare-exchange-int-seq-cst-relaxed.c |   1 +
 ...zalrsc-ztso-compare-exchange-int-seq-cst.c |   1 +
 gcc/testsuite/lib/target-supports.exp         |  25 +++-
 52 files changed, 949 insertions(+), 13 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zabha-zacas-preferred-over-zalrsc.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-char-requires-zabha.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-char-requires-zacas.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-preferred-over-zalrsc.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-acq-rel.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-acquire.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-relaxed.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-release.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-seq-cst.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-compatability-mapping-no-fence.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-compatability-mapping.cc
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-acq-rel.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-acquire.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-relaxed.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-release.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-seq-cst.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-acq-rel.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-acquire.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-relaxed.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-release.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-seq-cst.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-char-seq-cst.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-char.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-compatability-mapping-no-fence.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-compatability-mapping.cc
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-int-seq-cst.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-int.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-short-seq-cst.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-short.c

Comments

Patrick O'Neill July 24, 2024, 12:39 a.m. UTC | #1
>   (define_expand "atomic_compare_and_swap<mode>"
>     [(match_operand:SI 0 "register_operand" "")   ;; bool output
>      (match_operand:GPR 1 "register_operand" "")  ;; val output
>      (match_operand:GPR 2 "memory_operand" "")    ;; memory
> -   (match_operand:GPR 3 "reg_or_0_operand" "")  ;; expected value
> +   (match_operand:GPR 3 "register_operand" "")  ;; expected value
>      (match_operand:GPR 4 "reg_or_0_operand" "")  ;; desired value
>      (match_operand:SI 5 "const_int_operand" "")  ;; is_weak
>      (match_operand:SI 6 "const_int_operand" "")  ;; mod_s
>      (match_operand:SI 7 "const_int_operand" "")] ;; mod_f
<snip>
> -(define_expand "atomic_cas_value_strong<mode>"
> +(define_expand "zalrsc_atomic_cas_value_strong<mode>"
>     [(match_operand:SHORT 0 "register_operand") ;; val output
>      (match_operand:SHORT 1 "memory_operand")   ;; memory
>      (match_operand:SHORT 2 "reg_or_0_operand") ;; expected value

Wanted to highlight this for reviewers since it's non-obvious when
reading the diff:
`expected value` is now a `register_operand` since that's needed for
amocas as it reads/writes expected/actual value to the same register.

I left the zalrsc pattern as `reg_or_0_operand` even though it will
only be passed `register_operand` from the expander.
I think it captures the lr/sc pattern's requirements better but I'm
happy to change this if register_operand is preferred for the zalrsc case.

Patrick
Kito Cheng July 24, 2024, 2:48 a.m. UTC | #2
I incline do not add skip_zacas stuffs (although skip_zabha is already
there but that's fine), because that's different situation compare to
the zaamo/zalrsc, zaamo/zalrsc should automatically append if a
extension is available, which is new behavior and new extensions.

But zacas is only added when users explicitly add that in -march
string unlike zaamo/zalrsc, so I am not sure if we need to check the
binutils support and drop that if unsupported,

My biggest concern is : should we do so for every new extension?

I think we didn't do that so far, so we should
Patrick O'Neill July 24, 2024, 4:45 p.m. UTC | #3
On 7/23/24 19:48, Kito Cheng wrote:
> I incline do not add skip_zacas stuffs (although skip_zabha is already
> there but that's fine), because that's different situation compare to
> the zaamo/zalrsc, zaamo/zalrsc should automatically append if a
> extension is available, which is new behavior and new extensions.
>
> But zacas is only added when users explicitly add that in -march
> string unlike zaamo/zalrsc, so I am not sure if we need to check the
> binutils support and drop that if unsupported,
>
> My biggest concern is : should we do so for every new extension?
>
> I think we didn't do that so far, so we should
I included it since binutils only recently added support but you make a 
good point.
Failing explicitly for new extensions on outdated binutils makes sense 
to me.

If there aren't any objections I'll remove it from v3 and send a 
separate patch to
remove zabha so it's clear we only handle breaking changes to existing 
extensions.
Andrea Parri July 25, 2024, 12:57 p.m. UTC | #4
On Tue, Jul 23, 2024 at 05:15:44PM -0700, Patrick O'Neill wrote:
> From: Gianluca Guida <gianluca@rivosinc.com>
> 
> This patch adds support for amocas.{b|h|w|d}. Support for amocas.q
> (64/128 bit cas for rv32/64) will be added in a future patch.
> 
> Extension: https://github.com/riscv/riscv-zacas
> Ratification: https://jira.riscv.org/browse/RVS-680
> 
> gcc/ChangeLog:
> 
> 	* common/config/riscv/riscv-common.cc
> 	(riscv_subset_list::to_string): Skip zacas when not supported by
> 	the assembler.
> 	* config.in: Regenerate.
> 	* config/riscv/arch-canonicalize: Make zacas imply zaamo.
> 	* config/riscv/riscv.opt: Add zacas.
> 	* config/riscv/sync.md (zacas_atomic_cas_value<mode>): New pattern.
> 	(atomic_compare_and_swap<mode>): Use new pattern for compare-and-swap ops.
> 	(zalrsc_atomic_cas_value_strong<mode>): Rename atomic_cas_value_strong.
> 	* configure: Regenerate.
> 	* configure.ac: Regenerate.
> 	* doc/sourcebuild.texi: Add Zacas documentation.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* lib/target-supports.exp: Add zacas testsuite infra support.
> 	* gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-acquire-release.c:
> 	Remove zacas to continue to test the lr/sc pairs.
> 	* gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-acquire.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-consume.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-relaxed.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-release.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-seq-cst-relaxed.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-seq-cst.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-acquire-release.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-acquire.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-consume.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-relaxed.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-release.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-seq-cst-relaxed.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-seq-cst.c: Ditto.
> 	* gcc.target/riscv/amo/zabha-zacas-preferred-over-zalrsc.c: New test.
> 	* gcc.target/riscv/amo/zacas-char-requires-zabha.c: New test.
> 	* gcc.target/riscv/amo/zacas-char-requires-zacas.c: New test.
> 	* gcc.target/riscv/amo/zacas-preferred-over-zalrsc.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-acq-rel.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-acquire.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-relaxed.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-release.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-seq-cst.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-compatability-mapping-no-fence.c:
> 	New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-compatability-mapping.cc: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-acq-rel.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-acquire.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-relaxed.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-release.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-seq-cst.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-acq-rel.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-acquire.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-relaxed.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-release.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-seq-cst.c: New test.
> 	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-char-seq-cst.c: New test.
> 	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-char.c: New test.
> 	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-compatability-mapping-no-fence.c:
> 	New test.
> 	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-compatability-mapping.cc: New test.
> 	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-int-seq-cst.c: New test.
> 	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-int.c: New test.
> 	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-short-seq-cst.c: New test.
> 	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-short.c: New test.
> 
> Co-authored-by: Patrick O'Neill <patrick@rivosinc.com>

LGTM; feel free to add:

Tested-by: Andrea Parri <andrea@rivosinc.com>

  Andrea
Jeff Law July 26, 2024, 9:59 p.m. UTC | #5
On 7/23/24 6:39 PM, Patrick O'Neill wrote:
>>   (define_expand "atomic_compare_and_swap<mode>"
>>     [(match_operand:SI 0 "register_operand" "")   ;; bool output
>>      (match_operand:GPR 1 "register_operand" "")  ;; val output
>>      (match_operand:GPR 2 "memory_operand" "")    ;; memory
>> -   (match_operand:GPR 3 "reg_or_0_operand" "")  ;; expected value
>> +   (match_operand:GPR 3 "register_operand" "")  ;; expected value
>>      (match_operand:GPR 4 "reg_or_0_operand" "")  ;; desired value
>>      (match_operand:SI 5 "const_int_operand" "")  ;; is_weak
>>      (match_operand:SI 6 "const_int_operand" "")  ;; mod_s
>>      (match_operand:SI 7 "const_int_operand" "")] ;; mod_f
> <snip>
>> -(define_expand "atomic_cas_value_strong<mode>"
>> +(define_expand "zalrsc_atomic_cas_value_strong<mode>"
>>     [(match_operand:SHORT 0 "register_operand") ;; val output
>>      (match_operand:SHORT 1 "memory_operand")   ;; memory
>>      (match_operand:SHORT 2 "reg_or_0_operand") ;; expected value
> 
> Wanted to highlight this for reviewers since it's non-obvious when
> reading the diff:
> `expected value` is now a `register_operand` since that's needed for
> amocas as it reads/writes expected/actual value to the same register.
> 
> I left the zalrsc pattern as `reg_or_0_operand` even though it will
> only be passed `register_operand` from the expander.
> I think it captures the lr/sc pattern's requirements better but I'm
> happy to change this if register_operand is preferred for the zalrsc case.
No strong opinion.  Clearly we have to use register_operand if it's 
in/out.  As for pure inputs, using reg_or_0_operand  is on the margins 
for something like this.


Jeff
Jeff Law July 26, 2024, 10:05 p.m. UTC | #6
On 7/23/24 6:15 PM, Patrick O'Neill wrote:
> From: Gianluca Guida <gianluca@rivosinc.com>
> 
> This patch adds support for amocas.{b|h|w|d}. Support for amocas.q
> (64/128 bit cas for rv32/64) will be added in a future patch.
> 
> Extension: https://github.com/riscv/riscv-zacas
> Ratification: https://jira.riscv.org/browse/RVS-680
> 
> gcc/ChangeLog:
> 
> 	* common/config/riscv/riscv-common.cc
> 	(riscv_subset_list::to_string): Skip zacas when not supported by
> 	the assembler.
> 	* config.in: Regenerate.
> 	* config/riscv/arch-canonicalize: Make zacas imply zaamo.
> 	* config/riscv/riscv.opt: Add zacas.
> 	* config/riscv/sync.md (zacas_atomic_cas_value<mode>): New pattern.
> 	(atomic_compare_and_swap<mode>): Use new pattern for compare-and-swap ops.
> 	(zalrsc_atomic_cas_value_strong<mode>): Rename atomic_cas_value_strong.
> 	* configure: Regenerate.
> 	* configure.ac: Regenerate.
> 	* doc/sourcebuild.texi: Add Zacas documentation.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* lib/target-supports.exp: Add zacas testsuite infra support.
> 	* gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-acquire-release.c:
> 	Remove zacas to continue to test the lr/sc pairs.
> 	* gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-acquire.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-consume.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-relaxed.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-release.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-seq-cst-relaxed.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-seq-cst.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-acquire-release.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-acquire.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-consume.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-relaxed.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-release.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-seq-cst-relaxed.c: Ditto.
> 	* gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-seq-cst.c: Ditto.
> 	* gcc.target/riscv/amo/zabha-zacas-preferred-over-zalrsc.c: New test.
> 	* gcc.target/riscv/amo/zacas-char-requires-zabha.c: New test.
> 	* gcc.target/riscv/amo/zacas-char-requires-zacas.c: New test.
> 	* gcc.target/riscv/amo/zacas-preferred-over-zalrsc.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-acq-rel.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-acquire.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-relaxed.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-release.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-seq-cst.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-compatability-mapping-no-fence.c:
> 	New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-compatability-mapping.cc: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-acq-rel.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-acquire.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-relaxed.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-release.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-seq-cst.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-acq-rel.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-acquire.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-relaxed.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-release.c: New test.
> 	* gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-seq-cst.c: New test.
> 	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-char-seq-cst.c: New test.
> 	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-char.c: New test.
> 	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-compatability-mapping-no-fence.c:
> 	New test.
> 	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-compatability-mapping.cc: New test.
> 	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-int-seq-cst.c: New test.
> 	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-int.c: New test.
> 	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-short-seq-cst.c: New test.
> 	* gcc.target/riscv/amo/zacas-ztso-compare-exchange-short.c: New test.
> 
> Co-authored-by: Patrick O'Neill <patrick@rivosinc.com>
> ---
> V2 Changelog
> * Fix functional bug where expected amocas value wasn't initialized.
> * Add leading fence to zacas with seq_cst failure mode for PSABI
> compatability (and corresponding testcases).
> * Rename atomic_cas_value_strong to zalrsc_atomic_cas_value_strong.
> * Remove unneeded zabha from int testcases.
> * Add testcase functions that test weak compxchng.
> * Add testcase for non-zabha zacas preferred over lrsc.
> 
> Tested locally with zaamo, zalrsc, ztso, and zacas with amo.exp.
> ---


> @@ -530,16 +530,47 @@
>     [(set_attr "type" "multi")
>      (set (attr "length") (const_int 16))])
>   
> +;; Implement compare_exchange with a conservative leading fence when
> +;; model_failure is seq_cst.
> +;; This allows us to be compatible with the ISA manual Table A.6 and Table A.7
> +;; (A6C and A7).
> +;; More details: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/issues/444
> +(define_insn "zacas_atomic_cas_value_strong<mode>"
> +  [(set (match_operand:GPR 0 "register_operand" "=&r")			    ;; val output
> +	(match_operand:GPR 1 "memory_operand" "+A"))			    ;; memory
> +   (set (match_dup 1)
> +	(unspec_volatile:GPR [(match_operand:GPR 2 "register_operand" "0")  ;; expected val
> +			      (match_operand:GPR 3 "reg_or_0_operand" "rJ") ;; desired val
> +			      (match_operand:SI 4 "const_int_operand")	    ;; mod_s
> +			      (match_operand:SI 5 "const_int_operand")]	    ;; mod_f
> +	 UNSPEC_COMPARE_AND_SWAP))]
> +  "TARGET_ZACAS"
> +  {
> +    enum memmodel model_success = (enum memmodel) INTVAL (operands[4]);
> +    enum memmodel model_failure = (enum memmodel) INTVAL (operands[5]);
> +    /* Find the union of the two memory models so we can satisfy both success
> +       and failure memory models.  */
> +    operands[4] = GEN_INT (riscv_union_memmodels (model_success, model_failure));
> +
> +    if (model_failure == MEMMODEL_SEQ_CST)
> +      return "fence\trw,rw\;"
> +	     "amocas.<amo>%A4\t%0,%z3,%1";
> +    else
> +      return "amocas.<amo>%A4\t%0,%z3,%1";
> +  }
> +  [(set_attr "type" "atomic")
> +   (set (attr "length") (const_int 4))])
Doesn't the length need adjusting when we need to emit the leading fence?


;
>   })
>   
> +;; Implement compare_exchange with a conservative leading fence when
> +;; model_failure is seq_cst.
> +;; This allows us to be compatible with the ISA manual Table A.6 and Table A.7
> +;; (A6C and A7).
> +;; More details: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/issues/444
> +(define_insn "zacas_atomic_cas_value_strong<mode>"
> +  [(set (match_operand:SHORT 0 "register_operand" "=&r")			;; val output
> +	(match_operand:SHORT 1 "memory_operand" "+A"))				;; memory
> +   (set (match_dup 1)
> +	(unspec_volatile:SHORT [(match_operand:SHORT 2 "register_operand" "0")  ;; expected_val
> +				(match_operand:SHORT 3 "register_operand" "rJ") ;; desired_val
> +				(match_operand:SI 4 "const_int_operand")	;; mod_s
> +				(match_operand:SI 5 "const_int_operand")]	;; mod_f
> +	 UNSPEC_COMPARE_AND_SWAP))]
> +  "TARGET_ZACAS && TARGET_ZABHA"
> +  {
> +    enum memmodel model_success = (enum memmodel) INTVAL (operands[4]);
> +    enum memmodel model_failure = (enum memmodel) INTVAL (operands[5]);
> +    /* Find the union of the two memory models so we can satisfy both success
> +       and failure memory models.  */
> +    operands[4] = GEN_INT (riscv_union_memmodels (model_success, model_failure));
> +
> +    if (model_failure == MEMMODEL_SEQ_CST)
> +      return "fence\trw,rw\;"
> +	     "amocas.<amobh>%A4\t%0,%z3,%1";
> +    else
> +      return "amocas.<amobh>%A4\t%0,%z3,%1";
> +  }
> +  [(set_attr "type" "atomic")
> +   (set (attr "length") (const_int 4))])
Similarly here.


Otherwise I'm good with this patch.  I know Kito raised some concerns. 
So with the length fixes you just need to come to an agreement with Kito 
on how to handle the out-of-date binutils scenario.

jeff
diff mbox series

Patch

diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc
index 682826c0e34..dd318144274 100644
--- a/gcc/common/config/riscv/riscv-common.cc
+++ b/gcc/common/config/riscv/riscv-common.cc
@@ -95,6 +95,7 @@  static const riscv_implied_info_t riscv_implied_info[] =
    }},
 
   {"zabha", "zaamo"},
+  {"zacas", "zaamo"},
 
   {"b", "zba"},
   {"b", "zbb"},
@@ -283,6 +284,7 @@  static const struct riscv_ext_version riscv_ext_version_table[] =
   {"zaamo", ISA_SPEC_CLASS_NONE, 1, 0},
   {"zalrsc", ISA_SPEC_CLASS_NONE, 1, 0},
   {"zabha", ISA_SPEC_CLASS_NONE, 1, 0},
+  {"zacas", ISA_SPEC_CLASS_NONE, 1, 0},
 
   {"zba", ISA_SPEC_CLASS_NONE, 1, 0},
   {"zbb", ISA_SPEC_CLASS_NONE, 1, 0},
@@ -856,6 +858,7 @@  riscv_subset_list::to_string (bool version_p) const
   bool skip_zifencei = false;
   bool skip_zaamo_zalrsc = false;
   bool skip_zabha = false;
+  bool skip_zacas = false;
   bool skip_zicsr = false;
   bool i2p0 = false;
 
@@ -891,6 +894,10 @@  riscv_subset_list::to_string (bool version_p) const
   /* Skip since binutils 2.42 and earlier don't recognize zabha.  */
   skip_zabha = true;
 #endif
+#ifndef HAVE_AS_MARCH_ZACAS
+  /* Skip since binutils 2.42 and earlier don't recognize zacas.  */
+  skip_zacas = true;
+#endif
 
   for (subset = m_head; subset != NULL; subset = subset->next)
     {
@@ -911,6 +918,9 @@  riscv_subset_list::to_string (bool version_p) const
       if (skip_zabha && subset->name == "zabha")
 	continue;
 
+      if (skip_zacas && subset->name == "zacas")
+	continue;
+
       /* For !version_p, we only separate extension with underline for
 	 multi-letter extension.  */
       if (!first &&
@@ -1590,6 +1600,7 @@  static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
   {"zaamo",   &gcc_options::x_riscv_za_subext, MASK_ZAAMO},
   {"zalrsc",  &gcc_options::x_riscv_za_subext, MASK_ZALRSC},
   {"zabha",   &gcc_options::x_riscv_za_subext, MASK_ZABHA},
+  {"zacas",   &gcc_options::x_riscv_za_subext, MASK_ZACAS},
 
   {"zba",    &gcc_options::x_riscv_zb_subext, MASK_ZBA},
   {"zbb",    &gcc_options::x_riscv_zb_subext, MASK_ZBB},
diff --git a/gcc/config.in b/gcc/config.in
index bc819005bd6..4468fa70fd3 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -641,6 +641,12 @@ 
 #endif
 
 
+/* Define if the assembler understands -march=rv*_zacas. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_AS_MARCH_ZACAS
+#endif
+
+
 /* Define if the assembler understands -march=rv*_zifencei. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_AS_MARCH_ZIFENCEI
diff --git a/gcc/config/riscv/arch-canonicalize b/gcc/config/riscv/arch-canonicalize
index 2ea514dd986..35e0f46b6bd 100755
--- a/gcc/config/riscv/arch-canonicalize
+++ b/gcc/config/riscv/arch-canonicalize
@@ -43,6 +43,7 @@  IMPLIED_EXT = {
 
   "a" : ["zaamo", "zalrsc"],
   "zabha" : ["zaamo"],
+  "zacas" : ["zaamo"],
 
   "f" : ["zicsr"],
   "b" : ["zba", "zbb", "zbs"],
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index edf1c6d85f3..2e340e5324f 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -264,6 +264,8 @@  Mask(ZALRSC) Var(riscv_za_subext)
 
 Mask(ZABHA) Var(riscv_za_subext)
 
+Mask(ZACAS) Var(riscv_za_subext)
+
 Mask(ZA64RS)  Var(riscv_za_subext)
 
 Mask(ZA128RS) Var(riscv_za_subext)
diff --git a/gcc/config/riscv/sync.md b/gcc/config/riscv/sync.md
index 0470e2ca457..2dd9fd1ea85 100644
--- a/gcc/config/riscv/sync.md
+++ b/gcc/config/riscv/sync.md
@@ -503,7 +503,7 @@ 
 
 ; Atomic CAS ops
 
-(define_insn "atomic_cas_value_strong<mode>"
+(define_insn "zalrsc_atomic_cas_value_strong<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&r")
 	(match_operand:GPR 1 "memory_operand" "+A"))
    (set (match_dup 1)
@@ -530,16 +530,47 @@ 
   [(set_attr "type" "multi")
    (set (attr "length") (const_int 16))])
 
+;; Implement compare_exchange with a conservative leading fence when
+;; model_failure is seq_cst.
+;; This allows us to be compatible with the ISA manual Table A.6 and Table A.7
+;; (A6C and A7).
+;; More details: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/issues/444
+(define_insn "zacas_atomic_cas_value_strong<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=&r")			    ;; val output
+	(match_operand:GPR 1 "memory_operand" "+A"))			    ;; memory
+   (set (match_dup 1)
+	(unspec_volatile:GPR [(match_operand:GPR 2 "register_operand" "0")  ;; expected val
+			      (match_operand:GPR 3 "reg_or_0_operand" "rJ") ;; desired val
+			      (match_operand:SI 4 "const_int_operand")	    ;; mod_s
+			      (match_operand:SI 5 "const_int_operand")]	    ;; mod_f
+	 UNSPEC_COMPARE_AND_SWAP))]
+  "TARGET_ZACAS"
+  {
+    enum memmodel model_success = (enum memmodel) INTVAL (operands[4]);
+    enum memmodel model_failure = (enum memmodel) INTVAL (operands[5]);
+    /* Find the union of the two memory models so we can satisfy both success
+       and failure memory models.  */
+    operands[4] = GEN_INT (riscv_union_memmodels (model_success, model_failure));
+
+    if (model_failure == MEMMODEL_SEQ_CST)
+      return "fence\trw,rw\;"
+	     "amocas.<amo>%A4\t%0,%z3,%1";
+    else
+      return "amocas.<amo>%A4\t%0,%z3,%1";
+  }
+  [(set_attr "type" "atomic")
+   (set (attr "length") (const_int 4))])
+
 (define_expand "atomic_compare_and_swap<mode>"
   [(match_operand:SI 0 "register_operand" "")   ;; bool output
    (match_operand:GPR 1 "register_operand" "")  ;; val output
    (match_operand:GPR 2 "memory_operand" "")    ;; memory
-   (match_operand:GPR 3 "reg_or_0_operand" "")  ;; expected value
+   (match_operand:GPR 3 "register_operand" "")  ;; expected value
    (match_operand:GPR 4 "reg_or_0_operand" "")  ;; desired value
    (match_operand:SI 5 "const_int_operand" "")  ;; is_weak
    (match_operand:SI 6 "const_int_operand" "")  ;; mod_s
    (match_operand:SI 7 "const_int_operand" "")] ;; mod_f
-  "TARGET_ZALRSC"
+  "TARGET_ZALRSC || TARGET_ZACAS"
 {
   if (word_mode != <MODE>mode && operands[3] != const0_rtx)
     {
@@ -550,9 +581,20 @@ 
       operands[3] = simplify_gen_subreg (<MODE>mode, tmp0, word_mode, 0);
     }
 
-  emit_insn (gen_atomic_cas_value_strong<mode> (operands[1], operands[2],
-						operands[3], operands[4],
-						operands[6], operands[7]));
+  if (TARGET_ZACAS)
+    emit_insn (gen_zacas_atomic_cas_value_strong<mode> (operands[1],
+							operands[2],
+							operands[3],
+							operands[4],
+							operands[6],
+							operands[7]));
+  else
+    emit_insn (gen_zalrsc_atomic_cas_value_strong<mode> (operands[1],
+							 operands[2],
+							 operands[3],
+							 operands[4],
+							 operands[6],
+							 operands[7]));
 
   rtx compare = operands[1];
   if (operands[3] != const0_rtx)
@@ -573,20 +615,63 @@ 
   DONE;
 })
 
+;; Implement compare_exchange with a conservative leading fence when
+;; model_failure is seq_cst.
+;; This allows us to be compatible with the ISA manual Table A.6 and Table A.7
+;; (A6C and A7).
+;; More details: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/issues/444
+(define_insn "zacas_atomic_cas_value_strong<mode>"
+  [(set (match_operand:SHORT 0 "register_operand" "=&r")			;; val output
+	(match_operand:SHORT 1 "memory_operand" "+A"))				;; memory
+   (set (match_dup 1)
+	(unspec_volatile:SHORT [(match_operand:SHORT 2 "register_operand" "0")  ;; expected_val
+				(match_operand:SHORT 3 "register_operand" "rJ") ;; desired_val
+				(match_operand:SI 4 "const_int_operand")	;; mod_s
+				(match_operand:SI 5 "const_int_operand")]	;; mod_f
+	 UNSPEC_COMPARE_AND_SWAP))]
+  "TARGET_ZACAS && TARGET_ZABHA"
+  {
+    enum memmodel model_success = (enum memmodel) INTVAL (operands[4]);
+    enum memmodel model_failure = (enum memmodel) INTVAL (operands[5]);
+    /* Find the union of the two memory models so we can satisfy both success
+       and failure memory models.  */
+    operands[4] = GEN_INT (riscv_union_memmodels (model_success, model_failure));
+
+    if (model_failure == MEMMODEL_SEQ_CST)
+      return "fence\trw,rw\;"
+	     "amocas.<amobh>%A4\t%0,%z3,%1";
+    else
+      return "amocas.<amobh>%A4\t%0,%z3,%1";
+  }
+  [(set_attr "type" "atomic")
+   (set (attr "length") (const_int 4))])
+
 (define_expand "atomic_compare_and_swap<mode>"
   [(match_operand:SI 0 "register_operand")    ;; bool output
    (match_operand:SHORT 1 "register_operand") ;; val output
    (match_operand:SHORT 2 "memory_operand")   ;; memory
-   (match_operand:SHORT 3 "reg_or_0_operand") ;; expected value
+   (match_operand:SHORT 3 "register_operand") ;; expected value
    (match_operand:SHORT 4 "reg_or_0_operand") ;; desired value
    (match_operand:SI 5 "const_int_operand")   ;; is_weak
    (match_operand:SI 6 "const_int_operand")   ;; mod_s
    (match_operand:SI 7 "const_int_operand")]  ;; mod_f
-  "TARGET_ZALRSC && TARGET_INLINE_SUBWORD_ATOMIC"
+  "(TARGET_ZALRSC && TARGET_INLINE_SUBWORD_ATOMIC) || (TARGET_ZACAS && TARGET_ZABHA)"
 {
-  emit_insn (gen_atomic_cas_value_strong<mode> (operands[1], operands[2],
-						operands[3], operands[4],
-						operands[6], operands[7]));
+
+  if (TARGET_ZACAS && TARGET_ZABHA)
+    emit_insn (gen_zacas_atomic_cas_value_strong<mode> (operands[1],
+							operands[2],
+							operands[3],
+							operands[4],
+							operands[6],
+							operands[7]));
+  else
+    emit_insn (gen_zalrsc_atomic_cas_value_strong<mode> (operands[1],
+							 operands[2],
+							 operands[3],
+							 operands[4],
+							 operands[6],
+							 operands[7]));
 
   rtx val = gen_reg_rtx (SImode);
   if (operands[1] != const0_rtx)
@@ -619,7 +704,7 @@ 
   DONE;
 })
 
-(define_expand "atomic_cas_value_strong<mode>"
+(define_expand "zalrsc_atomic_cas_value_strong<mode>"
   [(match_operand:SHORT 0 "register_operand") ;; val output
    (match_operand:SHORT 1 "memory_operand")   ;; memory
    (match_operand:SHORT 2 "reg_or_0_operand") ;; expected value
diff --git a/gcc/configure b/gcc/configure
index 01acca7fb5c..24fe92d55d3 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -30913,6 +30913,37 @@  if test $gcc_cv_as_riscv_march_zabha = yes; then
 
 $as_echo "#define HAVE_AS_MARCH_ZABHA 1" >>confdefs.h
 
+fi
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for -march=rv32i_zacas support" >&5
+$as_echo_n "checking assembler for -march=rv32i_zacas support... " >&6; }
+if ${gcc_cv_as_riscv_march_zacas+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  gcc_cv_as_riscv_march_zacas=no
+  if test x$gcc_cv_as != x; then
+    $as_echo '' > conftest.s
+    if { ac_try='$gcc_cv_as $gcc_cv_as_flags -march=rv32i_zacas -o conftest.o conftest.s >&5'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+    then
+	gcc_cv_as_riscv_march_zacas=yes
+    else
+      echo "configure: failed program was" >&5
+      cat conftest.s >&5
+    fi
+    rm -f conftest.o conftest.s
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_riscv_march_zacas" >&5
+$as_echo "$gcc_cv_as_riscv_march_zacas" >&6; }
+if test $gcc_cv_as_riscv_march_zacas = yes; then
+
+$as_echo "#define HAVE_AS_MARCH_ZACAS 1" >>confdefs.h
+
 fi
 
     ;;
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 3f20c107b6a..28de7aa175a 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -5466,6 +5466,11 @@  configured with --enable-newlib-nano-formatted-io.])
       [-march=rv32i_zabha],,,
       [AC_DEFINE(HAVE_AS_MARCH_ZABHA, 1,
 		 [Define if the assembler understands -march=rv*_zabha.])])
+    gcc_GAS_CHECK_FEATURE([-march=rv32i_zacas support],
+      gcc_cv_as_riscv_march_zacas,
+      [-march=rv32i_zacas],,,
+      [AC_DEFINE(HAVE_AS_MARCH_ZACAS, 1,
+		 [Define if the assembler understands -march=rv*_zacas.])])
     ;;
     loongarch*-*-*)
     gcc_GAS_CHECK_FEATURE([.dtprelword support],
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index 66c4206bfc2..d5c48e67b71 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -2530,6 +2530,9 @@  Test target architecture has support for the zaamo extension.
 @item riscv_zabha
 Test target architecture has support for the zabha extension.
 
+@item riscv_zacas
+Test target architecture has support for the zacas extension.
+
 @item riscv_zalrsc
 Test target architecture has support for the zalrsc extension.
 
@@ -3298,6 +3301,9 @@  Add the zaamo extension to the -march string on RISC-V targets.
 @item riscv_zabha
 Add the zabha extension to the -march string on RISC-V targets.
 
+@item riscv_zacas
+Add the zacas extension to the -march string on RISC-V targets.
+
 @item riscv_zalrsc
 Add the zalrsc extension to the -march string on RISC-V targets.
 
@@ -3345,6 +3351,10 @@  extension is present downgrade it to zalrsc.
 Remove the zabha extension and implied zaamo extension from the -march string
 on RISC-V.
 
+@item riscv_zacas
+Remove the zacas extension and implied zaamo extension from the -march string
+on RISC-V.
+
 @item riscv_zalrsc
 Remove the zalrsc extension from the -march string on RISC-V. If the 'A'
 extension is present downgrade it to zaamo.
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zabha-zacas-preferred-over-zalrsc.c b/gcc/testsuite/gcc.target/riscv/amo/zabha-zacas-preferred-over-zalrsc.c
new file mode 100644
index 00000000000..a06e195c6d4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zabha-zacas-preferred-over-zalrsc.c
@@ -0,0 +1,21 @@ 
+/* { dg-do compile } */
+/* Ensure that AMO ops are emitted for subword cas when both zalrsc and
+   zacas/zabha are enabled.  */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zalrsc } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-add-options riscv_zabha } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.b\t" 2 } } */
+
+
+void atomic_compare_exchange_weak_char_relaxed (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_char_relaxed (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-char-requires-zabha.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-char-requires-zabha.c
new file mode 100644
index 00000000000..c7d6e7c578b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-char-requires-zabha.c
@@ -0,0 +1,17 @@ 
+/* { dg-do compile } */
+/* Ensure subword zacas is not emitted unless both zacas and zabha are
+   present.  */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-remove-options riscv_zabha } */
+/* { dg-remove-options riscv_zalrsc } */
+/* { dg-final { scan-assembler "\tcall\t" } } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-not "amocas\.b\t" } } */
+
+
+void atomic_compare_exchange_char_relaxed (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-char-requires-zacas.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-char-requires-zacas.c
new file mode 100644
index 00000000000..d0cf14432fe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-char-requires-zacas.c
@@ -0,0 +1,17 @@ 
+/* { dg-do compile } */
+/* Ensure subword zacas is not emitted unless both zacas and zabha are
+   present.  */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zabha } */
+/* { dg-remove-options riscv_zacas } */
+/* { dg-remove-options riscv_zalrsc } */
+/* { dg-final { scan-assembler "\tcall\t" } } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-not "amocas\.b\t" } } */
+
+
+void atomic_compare_exchange_char_relaxed (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-preferred-over-zalrsc.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-preferred-over-zalrsc.c
new file mode 100644
index 00000000000..9a995cca37f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-preferred-over-zalrsc.c
@@ -0,0 +1,20 @@ 
+/* { dg-do compile } */
+/* Ensure that AMO ops are emitted for subword cas when both zalrsc and
+   zacas/zabha are enabled.  */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zalrsc } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.w\t" 2 } } */
+
+
+void atomic_compare_exchange_weak_int_relaxed (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_int_relaxed (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-acq-rel.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-acq-rel.c
new file mode 100644
index 00000000000..b76385b4d26
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-acq-rel.c
@@ -0,0 +1,20 @@ 
+/* Verify that atomic op mappings match the PSABI doc's recommended mapping.  */
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zabha } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-remove-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.b\.aqrl\t" 2 } } */
+
+
+void atomic_compare_exchange_weak_char_acq_rel (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_char_acq_rel (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-acquire.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-acquire.c
new file mode 100644
index 00000000000..62ecf7b5fff
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-acquire.c
@@ -0,0 +1,20 @@ 
+/* Verify that atomic op mappings match the PSABI doc's recommended mapping.  */
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zabha } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-remove-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.b\.aq\t" 2 } } */
+
+
+void atomic_compare_exchange_weak_char_acquire (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
+}
+
+void atomic_compare_exchange_strong_char_acquire (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-relaxed.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-relaxed.c
new file mode 100644
index 00000000000..21c960c893b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-relaxed.c
@@ -0,0 +1,20 @@ 
+/* Verify that atomic op mappings match the PSABI doc's recommended mapping.  */
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zabha } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-remove-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.b\t" 2 } } */
+
+
+void atomic_compare_exchange_weak_char_relaxed (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_char_relaxed (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-release.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-release.c
new file mode 100644
index 00000000000..6b4083376ee
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-release.c
@@ -0,0 +1,20 @@ 
+/* Verify that atomic op mappings match the PSABI doc's recommended mapping.  */
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zabha } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-remove-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.b\.rl\t" 2 } } */
+
+
+void atomic_compare_exchange_weak_char_release (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_char_release (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_RELEASE, __ATOMIC_RELAXED);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-seq-cst.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-seq-cst.c
new file mode 100644
index 00000000000..289bdf44e9f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-char-seq-cst.c
@@ -0,0 +1,20 @@ 
+/* Verify that atomic op mappings match the PSABI doc's recommended mapping.  */
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zabha } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-remove-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.b\.aqrl\t" 2 } } */
+
+
+void atomic_compare_exchange_weak_char_seq_cst (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
+
+void atomic_compare_exchange_strong_char_seq_cst (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-compatability-mapping-no-fence.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-compatability-mapping-no-fence.c
new file mode 100644
index 00000000000..99fd7577a48
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-compatability-mapping-no-fence.c
@@ -0,0 +1,30 @@ 
+/*
+** Verify that atomic op mappings match the PSABI doc's recommended mapping.
+** compare_exchange ops without a seq_cst failure ordering do *not* need a
+** leading fence.
+*/
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-remove-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tfence" } } */
+
+void atomic_compare_exchange_weak_int_seq_cst_relaxed (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_weak_int_seq_cst_acquire (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE);
+}
+
+void atomic_compare_exchange_strong_int_seq_cst_relaxed (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_int_seq_cst_acquire (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-compatability-mapping.cc b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-compatability-mapping.cc
new file mode 100644
index 00000000000..c8d81299197
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-compatability-mapping.cc
@@ -0,0 +1,58 @@ 
+/*
+** Verify that atomic op mappings match the PSABI doc's recommended mapping.
+** compare_exchange ops with seq_cst failure ordering need a leading fence
+** to remain compatible with Table A.6 (A6C).
+*/
+/* { dg-do compile } */
+/* { dg-options "-O3 -std=c++17" } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-remove-options riscv_ztso } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+/*
+** atomic_compare_exchange_weak_int_relaxed_seq_cst:
+**	...
+**	fence\trw,rw
+**	amoadd\.w\.aqrl\t[atx][0-9]+,a2,0\(a0\)
+**	...
+*/
+void atomic_compare_exchange_weak_int_relaxed_seq_cst (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_RELAXED, __ATOMIC_SEQ_CST);
+}
+
+/*
+** atomic_compare_exchange_weak_int_seq_cst_seq_cst:
+**	...
+**	fence\trw,rw
+**	amoadd\.w\.aqrl\t[atx][0-9]+,a2,0\(a0\)
+**	...
+*/
+void atomic_compare_exchange_weak_int_seq_cst_seq_cst (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
+
+/*
+** atomic_compare_exchange_strong_int_relaxed_seq_cst:
+**	...
+**	fence\trw,rw
+**	amoadd\.w\.aqrl\t[atx][0-9]+,a2,0\(a0\)
+**	...
+*/
+void atomic_compare_exchange_strong_int_relaxed_seq_cst (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_RELAXED, __ATOMIC_SEQ_CST);
+}
+
+/*
+** atomic_compare_exchange_strong_int_seq_cst_seq_cst:
+**	...
+**	fence\trw,rw
+**	amoadd\.w\.aqrl\t[atx][0-9]+,a2,0\(a0\)
+**	...
+*/
+void atomic_compare_exchange_strong_int_seq_cst_seq_cst (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-acq-rel.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-acq-rel.c
new file mode 100644
index 00000000000..1b55c934962
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-acq-rel.c
@@ -0,0 +1,19 @@ 
+/* Verify that atomic op mappings match the PSABI doc's recommended mapping.  */
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-remove-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.w\.aqrl\t" 2 } } */
+
+
+void atomic_compare_exchange_weak_int_acq_rel (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_int_acq_rel (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-acquire.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-acquire.c
new file mode 100644
index 00000000000..8182360f244
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-acquire.c
@@ -0,0 +1,19 @@ 
+/* Verify that atomic op mappings match the PSABI doc's recommended mapping.  */
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-remove-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.w\.aq\t" 2 } } */
+
+
+void atomic_compare_exchange_weak_int_acquire (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
+}
+
+void atomic_compare_exchange_strong_int_acquire (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-relaxed.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-relaxed.c
new file mode 100644
index 00000000000..fb2a7b4f55a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-relaxed.c
@@ -0,0 +1,19 @@ 
+/* Verify that atomic op mappings match the PSABI doc's recommended mapping.  */
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-remove-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.w\t" 2 } } */
+
+
+void atomic_compare_exchange_weak_int_relaxed (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_int_relaxed (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-release.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-release.c
new file mode 100644
index 00000000000..756f5cbe7d1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-release.c
@@ -0,0 +1,19 @@ 
+/* Verify that atomic op mappings match the PSABI doc's recommended mapping.  */
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-remove-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.w\.rl\t" 2 } } */
+
+
+void atomic_compare_exchange_weak_int_release (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_int_release (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_RELEASE, __ATOMIC_RELAXED);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-seq-cst.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-seq-cst.c
new file mode 100644
index 00000000000..1c5b4ac0e2f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-int-seq-cst.c
@@ -0,0 +1,19 @@ 
+/* Verify that atomic op mappings match the PSABI doc's recommended mapping.  */
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-remove-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.w\.aqrl\t" 2 } } */
+
+
+void atomic_compare_exchange_weak_int_seq_cst (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
+
+void atomic_compare_exchange_strong_int_seq_cst (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-acq-rel.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-acq-rel.c
new file mode 100644
index 00000000000..2987eb3615d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-acq-rel.c
@@ -0,0 +1,20 @@ 
+/* Verify that atomic op mappings match the PSABI doc's recommended mapping.  */
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zabha } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-remove-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.h\.aqrl\t" 2 } } */
+
+
+void atomic_compare_exchange_weak_short_acq_rel (short *bar, short *baz, short qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_short_acq_rel (short *bar, short *baz, short qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-acquire.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-acquire.c
new file mode 100644
index 00000000000..505791090be
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-acquire.c
@@ -0,0 +1,20 @@ 
+/* Verify that atomic op mappings match the PSABI doc's recommended mapping.  */
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zabha } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-remove-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.h\.aq\t" 2 } } */
+
+
+void atomic_compare_exchange_weak_short_acquire (short *bar, short *baz, short qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
+}
+
+void atomic_compare_exchange_strong_short_acquire (short *bar, short *baz, short qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-relaxed.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-relaxed.c
new file mode 100644
index 00000000000..a85694e26c8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-relaxed.c
@@ -0,0 +1,20 @@ 
+/* Verify that atomic op mappings match the PSABI doc's recommended mapping.  */
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zabha } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-remove-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.h\t" 2 } } */
+
+
+void atomic_compare_exchange_weak_short_relaxed (short *bar, short *baz, short qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_short_relaxed (short *bar, short *baz, short qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-release.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-release.c
new file mode 100644
index 00000000000..e8e9aae0265
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-release.c
@@ -0,0 +1,20 @@ 
+/* Verify that atomic op mappings match the PSABI doc's recommended mapping.  */
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zabha } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-remove-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.h\.rl\t" 2 } } */
+
+
+void atomic_compare_exchange_weak_short_release (short *bar, short *baz, short qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_short_release (short *bar, short *baz, short qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_RELEASE, __ATOMIC_RELAXED);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-seq-cst.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-seq-cst.c
new file mode 100644
index 00000000000..d676d378e06
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-rvwmo-compare-exchange-short-seq-cst.c
@@ -0,0 +1,20 @@ 
+/* Verify that atomic op mappings match the PSABI doc's recommended mapping.  */
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zabha } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-remove-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.h\.aqrl\t" 2 } } */
+
+
+void atomic_compare_exchange_weak_short_seq_cst (short *bar, short *baz, short qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
+
+void atomic_compare_exchange_strong_short_seq_cst (short *bar, short *baz, short qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-char-seq-cst.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-char-seq-cst.c
new file mode 100644
index 00000000000..e219bd14b15
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-char-seq-cst.c
@@ -0,0 +1,19 @@ 
+/* Verify that atomic op mappings match the PSABI doc's recommended mapping.  */
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zabha } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-add-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.b\t" 2 } } */
+
+void atomic_compare_exchange_weak_char_seq_cst (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
+
+void atomic_compare_exchange_strong_char_seq_cst (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-char.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-char.c
new file mode 100644
index 00000000000..183dc4020c7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-char.c
@@ -0,0 +1,49 @@ 
+/* Verify that atomic op mappings match the PSABI doc's recommended mapping.  */
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zabha } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-add-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.b\t" 8 } } */
+
+void atomic_compare_exchange_weak_char_relaxed (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_char_relaxed (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_weak_char_acquire (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
+}
+
+void atomic_compare_exchange_strong_char_acquire (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
+}
+
+void atomic_compare_exchange_weak_char_release (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_char_release (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_RELEASE, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_weak_char_acq_rel (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_char_acq_rel (char *bar, char *baz, char qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-compatability-mapping-no-fence.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-compatability-mapping-no-fence.c
new file mode 100644
index 00000000000..2712eff5107
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-compatability-mapping-no-fence.c
@@ -0,0 +1,30 @@ 
+/*
+** Verify that atomic op mappings match the PSABI doc's recommended mapping.
+** compare_exchange ops without a seq_cst failure ordering do *not* need a
+** leading fence.
+*/
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-add-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tfence" } } */
+
+void atomic_compare_exchange_weak_int_seq_cst_relaxed (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_weak_int_seq_cst_acquire (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE);
+}
+
+void atomic_compare_exchange_strong_int_seq_cst_relaxed (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_int_seq_cst_acquire (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-compatability-mapping.cc b/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-compatability-mapping.cc
new file mode 100644
index 00000000000..560172bfbed
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-compatability-mapping.cc
@@ -0,0 +1,58 @@ 
+/*
+** Verify that atomic op mappings match the PSABI doc's recommended mapping.
+** compare_exchange ops with seq_cst failure ordering need a leading fence
+** to remain compatible with Table A.6 (A6C).
+*/
+/* { dg-do compile } */
+/* { dg-options "-O3 -std=c++17" } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-add-options riscv_ztso } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+/*
+** atomic_compare_exchange_weak_int_relaxed_seq_cst:
+**	...
+**	fence\trw,rw
+**	amoadd\.w\t[atx][0-9]+,a2,0\(a0\)
+**	...
+*/
+void atomic_compare_exchange_weak_int_relaxed_seq_cst (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_RELAXED, __ATOMIC_SEQ_CST);
+}
+
+/*
+** atomic_compare_exchange_weak_int_seq_cst_seq_cst:
+**	...
+**	fence\trw,rw
+**	amoadd\.w\t[atx][0-9]+,a2,0\(a0\)
+**	...
+*/
+void atomic_compare_exchange_weak_int_seq_cst_seq_cst (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
+
+/*
+** atomic_compare_exchange_strong_int_relaxed_seq_cst:
+**	...
+**	fence\trw,rw
+**	amoadd\.w\t[atx][0-9]+,a2,0\(a0\)
+**	...
+*/
+void atomic_compare_exchange_strong_int_relaxed_seq_cst (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_RELAXED, __ATOMIC_SEQ_CST);
+}
+
+/*
+** atomic_compare_exchange_strong_int_seq_cst_seq_cst:
+**	...
+**	fence\trw,rw
+**	amoadd\.w\t[atx][0-9]+,a2,0\(a0\)
+**	...
+*/
+void atomic_compare_exchange_strong_int_seq_cst_seq_cst (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-int-seq-cst.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-int-seq-cst.c
new file mode 100644
index 00000000000..1ee6cc20218
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-int-seq-cst.c
@@ -0,0 +1,18 @@ 
+/* Verify that atomic op mappings match the PSABI doc's recommended mapping.  */
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-add-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.w\t" 2 } } */
+
+void atomic_compare_exchange_weak_int_seq_cst (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
+
+void atomic_compare_exchange_strong_int_seq_cst (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-int.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-int.c
new file mode 100644
index 00000000000..2c332623a95
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-int.c
@@ -0,0 +1,48 @@ 
+/* Verify that atomic op mappings match the PSABI doc's recommended mapping.  */
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-add-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.w\t" 8 } } */
+
+void atomic_compare_exchange_weak_int_relaxed (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_int_relaxed (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_weak_int_acquire (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
+}
+
+void atomic_compare_exchange_strong_int_acquire (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
+}
+
+void atomic_compare_exchange_weak_int_release (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_int_release (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_RELEASE, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_weak_int_acq_rel (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_int_acq_rel (int *bar, int *baz, int qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-short-seq-cst.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-short-seq-cst.c
new file mode 100644
index 00000000000..1938448183c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-short-seq-cst.c
@@ -0,0 +1,19 @@ 
+/* Verify that atomic op mappings match the PSABI doc's recommended mapping.  */
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zabha } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-add-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.h\t" 2 } } */
+
+void atomic_compare_exchange_weak_short_seq_cst (short *bar, short *baz, short qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
+
+void atomic_compare_exchange_strong_short_seq_cst (short *bar, short *baz, short qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-short.c b/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-short.c
new file mode 100644
index 00000000000..69fe5ae3eac
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/amo/zacas-ztso-compare-exchange-short.c
@@ -0,0 +1,49 @@ 
+/* Verify that atomic op mappings match the PSABI doc's recommended mapping.  */
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-add-options riscv_zabha } */
+/* { dg-add-options riscv_zacas } */
+/* { dg-add-options riscv_ztso } */
+/* { dg-final { scan-assembler-not "\tlr\.w" } } */
+/* { dg-final { scan-assembler-not "\tsc\.w" } } */
+/* { dg-final { scan-assembler-times "amocas\.h\t" 8 } } */
+
+void atomic_compare_exchange_weak_short_relaxed (short *bar, short *baz, short qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_short_relaxed (short *bar, short *baz, short qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_weak_short_acquire (short *bar, short *baz, short qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
+}
+
+void atomic_compare_exchange_strong_short_acquire (short *bar, short *baz, short qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
+}
+
+void atomic_compare_exchange_weak_short_release (short *bar, short *baz, short qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_short_release (short *bar, short *baz, short qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_RELEASE, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_weak_short_acq_rel (short *bar, short *baz, short qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 0, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
+}
+
+void atomic_compare_exchange_strong_short_acq_rel (short *bar, short *baz, short qux)
+{
+  __atomic_compare_exchange_n(bar, baz, qux, 1, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-acquire-release.c b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-acquire-release.c
index 49eeda9cb33..9a5616f8916 100644
--- a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-acquire-release.c
+++ b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-acquire-release.c
@@ -2,6 +2,7 @@ 
 /* Verify that compare exchange mappings match the PSABI doc's recommended mapping.  */
 /* { dg-add-options riscv_zalrsc } */
 /* { dg-remove-options riscv_ztso } */
+/* { dg-remove-options riscv_zacas } */
 /* Mixed mappings need to be unioned.  */
 /* { dg-final { scan-assembler-times "lr.w.aq\t" 1 } } */
 /* { dg-final { scan-assembler-times "sc.w.rl\t" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-acquire.c b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-acquire.c
index b9e3adece8d..a24234855e9 100644
--- a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-acquire.c
+++ b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-acquire.c
@@ -2,6 +2,7 @@ 
 /* Verify that compare exchange mappings match the PSABI doc's recommended mapping.  */
 /* { dg-add-options riscv_zalrsc } */
 /* { dg-remove-options riscv_ztso } */
+/* { dg-remove-options riscv_zacas } */
 /* { dg-final { scan-assembler-times "lr.w.aq\t" 1 } } */
 /* { dg-final { scan-assembler-times "sc.w\t" 1 } } */
 
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-consume.c b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-consume.c
index 11839d84f14..18f53c83a38 100644
--- a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-consume.c
+++ b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-consume.c
@@ -2,6 +2,7 @@ 
 /* Verify that compare exchange mappings match the PSABI doc's recommended mapping.  */
 /* { dg-add-options riscv_zalrsc } */
 /* { dg-remove-options riscv_ztso } */
+/* { dg-remove-options riscv_zacas } */
 /* { dg-final { scan-assembler-times "lr.w.aq\t" 1 } } */
 /* { dg-final { scan-assembler-times "sc.w\t" 1 } } */
 
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-relaxed.c b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-relaxed.c
index 852ec99df76..c7a43ecd323 100644
--- a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-relaxed.c
+++ b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-relaxed.c
@@ -2,6 +2,7 @@ 
 /* Verify that compare exchange mappings match the PSABI doc's recommended mapping.  */
 /* { dg-add-options riscv_zalrsc } */
 /* { dg-remove-options riscv_ztso } */
+/* { dg-remove-options riscv_zacas } */
 /* { dg-final { scan-assembler-times "lr.w\t" 1 } } */
 /* { dg-final { scan-assembler-times "sc.w\t" 1 } } */
 
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-release.c b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-release.c
index 9c51a082d0b..302fca2ca17 100644
--- a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-release.c
+++ b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-release.c
@@ -2,6 +2,7 @@ 
 /* Verify that compare exchange mappings match the PSABI doc's recommended mapping.  */
 /* { dg-add-options riscv_zalrsc } */
 /* { dg-remove-options riscv_ztso } */
+/* { dg-remove-options riscv_zacas } */
 /* { dg-final { scan-assembler-times "lr.w\t" 1 } } */
 /* { dg-final { scan-assembler-times "sc.w.rl\t" 1 } } */
 
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-seq-cst-relaxed.c b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-seq-cst-relaxed.c
index d985e2cef8b..e62002d267a 100644
--- a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-seq-cst-relaxed.c
+++ b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-seq-cst-relaxed.c
@@ -3,6 +3,7 @@ 
 /* Mixed mappings need to be unioned.  */
 /* { dg-add-options riscv_zalrsc } */
 /* { dg-remove-options riscv_ztso } */
+/* { dg-remove-options riscv_zacas } */
 /* { dg-final { scan-assembler-times "lr.w.aqrl\t" 1 } } */
 /* { dg-final { scan-assembler-times "sc.w.rl\t" 1 } } */
 
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-seq-cst.c b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-seq-cst.c
index 6efd232ce21..c047d509aaf 100644
--- a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-seq-cst.c
+++ b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-rvwmo-compare-exchange-int-seq-cst.c
@@ -2,6 +2,7 @@ 
 /* Verify that compare exchange mappings match the PSABI doc's recommended mapping.  */
 /* { dg-add-options riscv_zalrsc } */
 /* { dg-remove-options riscv_ztso } */
+/* { dg-remove-options riscv_zacas } */
 /* { dg-final { scan-assembler-times "lr.w.aqrl\t" 1 } } */
 /* { dg-final { scan-assembler-times "sc.w.rl\t" 1 } } */
 
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-acquire-release.c b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-acquire-release.c
index 9761a955ede..496af8bfd7d 100644
--- a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-acquire-release.c
+++ b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-acquire-release.c
@@ -3,6 +3,7 @@ 
 /* Mixed mappings need to be unioned.  */
 /* { dg-add-options riscv_zalrsc } */
 /* { dg-add-options riscv_ztso } */
+/* { dg-remove-options riscv_zacas } */
 /* { dg-final { scan-assembler-times "lr.w\t" 1 } } */
 /* { dg-final { scan-assembler-times "sc.w\t" 1 } } */
 
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-acquire.c b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-acquire.c
index 3303f8021e1..737e3eb3d68 100644
--- a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-acquire.c
+++ b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-acquire.c
@@ -2,6 +2,7 @@ 
 /* Verify that compare exchange mappings match the PSABI doc's recommended mapping.  */
 /* { dg-add-options riscv_zalrsc } */
 /* { dg-add-options riscv_ztso } */
+/* { dg-remove-options riscv_zacas } */
 /* { dg-final { scan-assembler-times "lr.w\t" 1 } } */
 /* { dg-final { scan-assembler-times "sc.w\t" 1 } } */
 
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-consume.c b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-consume.c
index 7474e832bb1..51b3b5a8dc7 100644
--- a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-consume.c
+++ b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-consume.c
@@ -2,6 +2,7 @@ 
 /* Verify that compare exchange mappings match the PSABI doc's recommended mapping.  */
 /* { dg-add-options riscv_zalrsc } */
 /* { dg-add-options riscv_ztso } */
+/* { dg-remove-options riscv_zacas } */
 /* { dg-final { scan-assembler-times "lr.w\t" 1 } } */
 /* { dg-final { scan-assembler-times "sc.w\t" 1 } } */
 
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-relaxed.c b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-relaxed.c
index e43193820f2..9a41410a57b 100644
--- a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-relaxed.c
+++ b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-relaxed.c
@@ -2,6 +2,7 @@ 
 /* Verify that compare exchange mappings match the PSABI doc's recommended mapping.  */
 /* { dg-add-options riscv_zalrsc } */
 /* { dg-add-options riscv_ztso } */
+/* { dg-remove-options riscv_zacas } */
 /* { dg-final { scan-assembler-times "lr.w\t" 1 } } */
 /* { dg-final { scan-assembler-times "sc.w\t" 1 } } */
 
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-release.c b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-release.c
index a0d5872e1bd..ee778a760d1 100644
--- a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-release.c
+++ b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-release.c
@@ -2,6 +2,7 @@ 
 /* Verify that compare exchange mappings match the PSABI doc's recommended mapping.  */
 /* { dg-add-options riscv_zalrsc } */
 /* { dg-add-options riscv_ztso } */
+/* { dg-remove-options riscv_zacas } */
 /* { dg-final { scan-assembler-times "lr.w\t" 1 } } */
 /* { dg-final { scan-assembler-times "sc.w\t" 1 } } */
 
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-seq-cst-relaxed.c b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-seq-cst-relaxed.c
index fc464ab1ff5..6fbe943b316 100644
--- a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-seq-cst-relaxed.c
+++ b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-seq-cst-relaxed.c
@@ -3,6 +3,7 @@ 
 /* Mixed mappings need to be unioned.  */
 /* { dg-add-options riscv_zalrsc } */
 /* { dg-add-options riscv_ztso } */
+/* { dg-remove-options riscv_zacas } */
 /* { dg-final { scan-assembler-times "lr.w.aqrl\t" 1 } } */
 /* { dg-final { scan-assembler-times "sc.w.rl\t" 1 } } */
 
diff --git a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-seq-cst.c b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-seq-cst.c
index 152806cfde3..a361c10086d 100644
--- a/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-seq-cst.c
+++ b/gcc/testsuite/gcc.target/riscv/amo/zalrsc-ztso-compare-exchange-int-seq-cst.c
@@ -2,6 +2,7 @@ 
 /* Verify that compare exchange mappings match the PSABI doc's recommended mapping.  */
 /* { dg-add-options riscv_zalrsc } */
 /* { dg-add-options riscv_ztso } */
+/* { dg-remove-options riscv_zacas } */
 /* { dg-final { scan-assembler-times "lr.w.aqrl\t" 1 } } */
 /* { dg-final { scan-assembler-times "sc.w.rl\t" 1 } } */
 
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index d368251ef9a..f8e5f5f36d0 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -1922,6 +1922,17 @@  proc check_effective_target_riscv_zabha { } {
     }]
 }
 
+# Return 1 if the target arch supports the atomic CAS extension, 0 otherwise.
+# Cache the result.
+
+proc check_effective_target_riscv_zacas { } {
+    return [check_no_compiler_messages riscv_ext_zacas assembly {
+       #ifndef __riscv_zacas
+       #error "Not __riscv_zacas"
+       #endif
+    }]
+}
+
 # Return 1 if the target arch supports the double precision floating point
 # extension, 0 otherwise.  Cache the result.
 
@@ -2140,7 +2151,7 @@  proc check_effective_target_riscv_v_misalign_ok { } {
 proc riscv_get_arch { } {
     set gcc_march ""
     # ??? do we neeed to add more extensions to the list below?
-    foreach ext { i m a f d q c b v zicsr zifencei zfh zba zbb zbc zbs zvbb zvfh ztso zaamo zalrsc zabha } {
+    foreach ext { i m a f d q c b v zicsr zifencei zfh zba zbb zbc zbs zvbb zvfh ztso zaamo zalrsc zabha zacas } {
 	if { [check_no_compiler_messages  riscv_ext_$ext assembly [string map [list DEF __riscv_$ext] {
 		#ifndef DEF
 		#error "Not DEF"
@@ -2308,6 +2319,9 @@  proc remove_options_for_riscv_zaamo { flags } {
     # If zabha is set then zaamo will be implied. We need to remove zabha
     # as well.
     set modified_flags [remove_options_for_riscv_z_ext zabha $modified_flags]
+    # If zacas is set then zaamo will be implied. We need to remove zacas
+    # as well.
+    set modified_flags [remove_options_for_riscv_z_ext zacas $modified_flags]
     # If 'a' is set then zaamo will be implied. We need to downgrade instances
     # of 'a' to 'zalrsc'
     set no_a_flags [remove_options_for_riscv_a_only $modified_flags]
@@ -2343,6 +2357,15 @@  proc remove_options_for_riscv_zabha { flags } {
     return [remove_options_for_riscv_z_ext zabha $modified_flags]
 }
 
+proc add_options_for_riscv_zacas { flags } {
+    return [add_options_for_riscv_z_ext zacas $flags]
+}
+
+proc remove_options_for_riscv_zacas { flags } {
+    set modified_flags [remove_options_for_riscv_zaamo $flags]
+    return [remove_options_for_riscv_z_ext zacas $modified_flags]
+}
+
 proc add_options_for_riscv_zfh { flags } {
     return [add_options_for_riscv_z_ext zfh $flags]
 }