In PR 124741, we have a testcase:
typedef struct
{
int x;
unsigned repr;
} atomic_u_t;
unsigned
atomic_load_u (const atomic_u_t *a)
{
unsigned result;
__atomic_load (&a->repr, &result, 0);
return result;
}
When compiled with rv64, it outputs:
addi a5,a0,4
lw a0,0(a5)
sext.w a0,a0
ret
Here we have a redundant sign extension and inefficient address arithmetic.
This can be simplified into two instructions, a load and a return.
The lw insn is already doing a sign extension from 32 to 64 bits, making
the separate sext.w unnecessary. Adding a copy of the pattern that
explicitly shows the sign extension in the RTL, with the modes adjusted
accordingly, no longer emits the sext.w insn. I also generalized the
pattern to
support both sign and zero extension. These changes have been reflected
on the total store ordering memory consistency model as well. As Zalrsc
doesn't support zero extending load-acquire instructions, I introduced a new
iterator, ensuring zero extend is limited to !TARGET_ZALRSC for load.
The addi and lw are combined into lw a0,4(a5) by adjusting the memory
operand constraint to handle offsets in the load patterns. The validity of
the memory operand constraint depends on the value of operand 2 - the
memory model. I introduced new constraint alternatives, such that the
behavior of the memory operand constraint is triggered on whether the
memory model acquire is being used or not and the Zalrsc or non-Zalrsc
targets accordingly. Similar changes were made for the store patterns
where the inefficient address arithmetic problem was also present.
--
THanks Shreya. I've reviewed and made adjustments to the testsuite so that
the tests are working consistently on rv32 and rv64 and pushed this to
the trunk.
Jeff
commit b6bebf2a7326e6b5566f1aa2979233a60e5c8377
Author: Shreya Munnangi <[email protected]>
Date: Mon Jul 20 07:02:48 2026 -0600
[PATCH][RISC-V][PR target/124741] Improving atomic sequences
In PR 124741, we have a testcase:
typedef struct
{
int x;
unsigned repr;
} atomic_u_t;
unsigned
atomic_load_u (const atomic_u_t *a)
{
unsigned result;
__atomic_load (&a->repr, &result, 0);
return result;
}
When compiled with rv64, it outputs:
addi a5,a0,4
lw a0,0(a5)
sext.w a0,a0
ret
Here we have a redundant sign extension and inefficient address arithmetic.
This can be simplified into two instructions, a load and a return.
The lw insn is already doing a sign extension from 32 to 64 bits, making
the separate sext.w unnecessary. Adding a copy of the pattern that
explicitly shows the sign extension in the RTL, with the modes adjusted
accordingly, no longer emits the sext.w insn. I also generalized the
pattern to
support both sign and zero extension. These changes have been reflected
on the total store ordering memory consistency model as well. As Zalrsc
doesn't support zero extending load-acquire instructions, I introduced a new
iterator, ensuring zero extend is limited to !TARGET_ZALRSC for load.
The addi and lw are combined into lw a0,4(a5) by adjusting the memory
operand constraint to handle offsets in the load patterns. The validity of
the memory operand constraint depends on the value of operand 2 - the
memory model. I introduced new constraint alternatives, such that the
behavior of the memory operand constraint is triggered on whether the
memory model acquire is being used or not and the Zalrsc or non-Zalrsc
targets accordingly. Similar changes were made for the store patterns
where the inefficient address arithmetic problem was also present.
PR target/124741
gcc/
* config/riscv/constraints.md (B1, B2, B3, B4): New constraints for
atomic loads with and without ZALASR & MEMMODEL_ACQUIRE.
* config/riscv/iterators.md (cond_extend): New iterator to for use
in extending atomic loads.
* config/riscv/sync-rvwmo.md (atomic_load_rvwmo<mode>): Adjust
contraints to enable folding small offsets into memory load.
(atomic_store_rvwmo): Likewise.
(extending atomic_load_rvwmo): New pattern.
* config/riscv/sync-ztso.md (atomic_load_ztso<mode>): Adjust
constraints to enable folding small offsets into memory load.
(atomic_store_ztso): Likewise.
(extending atomic_load_ztso): New pattern.
gcc/testsuite/
* gcc.target/riscv/load-zalasr.c: Testcases for atomic load compiled
with rv64 and zalasr ext.
* gcc.target/riscv/load.c: Testcases for atomic load compiled with
rv64.
* gcc.target/riscv/load32-zalasr.c: Testcases for atomic load
compiled with rv32 and zalasr ext.
* gcc.target/riscv/load32.c: Testcases for atomic load compiled with
rv32.
* gcc.target/riscv/store-zalasr.c: Testcases for atomic store
compiled with rv64 and zalasr ext.
* gcc.target/riscv/store.c: Testcases for atomic store compiled
with rv64.
* gcc.target/riscv/store32-zalasr.c: Testcases for atomic store
compiled with rv32 and zalasr ext.
* gcc.target/riscv/store32.c: Testcases for atomic store compiled
with rv32.
Co-authored-by: Jeff Law <[email protected]>
diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md
index 8051c1e330b..d9fc9704ef5 100644
--- a/gcc/config/riscv/constraints.md
+++ b/gcc/config/riscv/constraints.md
@@ -145,6 +145,32 @@ (define_memory_constraint "A"
(and (match_code "mem")
(match_test "GET_CODE(XEXP(op,0)) == REG")))
+(define_constraint "B1"
+ "Memory models that can match with A for load."
+ (and (match_code "const_int")
+ (and (match_test "ival == MEMMODEL_ACQUIRE")
+ (match_test "TARGET_ZALASR"))))
+
+(define_constraint "B2"
+ "Memory models that can match with m for load."
+ (and (match_code "const_int")
+ (ior (match_test "ival != MEMMODEL_ACQUIRE")
+ (match_test "!TARGET_ZALASR"))))
+
+(define_constraint "B3"
+ "Memory models that can match with A for store."
+ (and (match_code "const_int")
+ (and (ior (match_test "ival == MEMMODEL_RELEASE")
+ (match_test "ival == MEMMODEL_SEQ_CST"))
+ (match_test "TARGET_ZALASR"))))
+
+(define_constraint "B4"
+ "Memory models that can match with m for store."
+ (and (match_code "const_int")
+ (ior (and (match_test "ival != MEMMODEL_RELEASE")
+ (match_test "ival != MEMMODEL_SEQ_CST"))
+ (match_test "!TARGET_ZALASR"))))
+
(define_constraint "S"
"A constraint that matches an absolute symbolic address."
(match_operand 0 "absolute_symbolic_operand"))
diff --git a/gcc/config/riscv/iterators.md b/gcc/config/riscv/iterators.md
index 076911e5e7f..dc25dfd2e99 100644
--- a/gcc/config/riscv/iterators.md
+++ b/gcc/config/riscv/iterators.md
@@ -207,6 +207,9 @@ (define_mode_attr slot12_offset [(SI "-52") (DI "-104")])
;; This code iterator allows signed and unsigned widening multiplications
;; to use the same template.
(define_code_iterator any_extend [sign_extend zero_extend])
+
+(define_code_iterator cond_extend [sign_extend (zero_extend "!TARGET_ZALASR")])
+
(define_code_attr extend_name [
(sign_extend "extend") (zero_extend "zero_extend")
])
diff --git a/gcc/config/riscv/sync-rvwmo.md b/gcc/config/riscv/sync-rvwmo.md
index 3d409388837..5519f2ac015 100644
--- a/gcc/config/riscv/sync-rvwmo.md
+++ b/gcc/config/riscv/sync-rvwmo.md
@@ -47,10 +47,10 @@ (define_insn "mem_thread_fence_rvwmo"
;; Atomic memory operations.
(define_insn "atomic_load_rvwmo<mode>"
- [(set (match_operand:ANYI 0 "register_operand" "=r")
+ [(set (match_operand:ANYI 0 "register_operand" "=r,r")
(unspec_volatile:ANYI
- [(match_operand:ANYI 1 "memory_operand" "A")
- (match_operand:SI 2 "const_int_operand")] ;; model
+ [(match_operand:ANYI 1 "memory_operand" "m,A")
+ (match_operand:SI 2 "const_int_operand" "B2,B1")]
UNSPECV_ATOMIC_LOAD))]
"!TARGET_ZTSO"
{
@@ -74,13 +74,43 @@ (define_insn "atomic_load_rvwmo<mode>"
: is_mm_acquire (memmodel_from_int (INTVAL
(operands[2]))) ? 8
: 4)"))])
+(define_insn "atomic_load_rvwmo<X:mode><SUBX:mode><code>"
+ [(set (match_operand:X 0 "register_operand" "=r,r")
+ (cond_extend:X
+ (unspec_volatile:SUBX
+ [(match_operand:SUBX 1 "memory_operand" "m,A")
+ (match_operand:SUBX 2 "const_int_operand" "B2,B1")]
+ UNSPECV_ATOMIC_LOAD)))]
+ "!TARGET_ZTSO"
+ {
+ enum memmodel model = (enum memmodel) INTVAL (operands[2]);
+ model = memmodel_base (model);
+
+ if (model == MEMMODEL_SEQ_CST)
+ return "fence\trw,rw\;"
+ "<SUBX:load><u>\t%0,%1\;"
+ "fence\tr,rw";
+ if (TARGET_ZALASR && model == MEMMODEL_ACQUIRE)
+ return "<SUBX:load><u>.aq\t%0,%1";
+ if (model == MEMMODEL_ACQUIRE)
+ return "<SUBX:load><u>\t%0,%1\;"
+ "fence\tr,rw";
+ else
+ return "<SUBX:load><u>\t%0,%1";
+ }
+ [(set_attr "type" "multi")
+ (set (attr "length")
+ (symbol_ref "(is_mm_seq_cst (memmodel_from_int (INTVAL (operands[2])))
? 12
+ : is_mm_acquire (memmodel_from_int (INTVAL
(operands[2]))) ? 8
+ : 4)"))])
+
;; Implement atomic stores with conservative fences.
;; This allows us to be compatible with the ISA manual Table A.6 and Table A.7.
(define_insn "atomic_store_rvwmo<mode>"
- [(set (match_operand:ANYI 0 "memory_operand" "=A")
+ [(set (match_operand:ANYI 0 "memory_operand" "=m,A")
(unspec_volatile:ANYI
- [(match_operand:ANYI 1 "reg_or_0_operand" "rJ")
- (match_operand:SI 2 "const_int_operand")] ;; model
+ [(match_operand:ANYI 1 "reg_or_0_operand" "rJ,rJ")
+ (match_operand:SI 2 "const_int_operand" "B4,B3")]
UNSPECV_ATOMIC_STORE))]
"!TARGET_ZTSO"
{
@@ -90,7 +120,6 @@ (define_insn "atomic_store_rvwmo<mode>"
if (TARGET_ZALASR
&& (model == MEMMODEL_RELEASE || model == MEMMODEL_SEQ_CST))
return "<store>.rl\t%z1,%0";
-
if (model == MEMMODEL_SEQ_CST)
return "fence\trw,w\;"
"<store>\t%z1,%0\;"
diff --git a/gcc/config/riscv/sync-ztso.md b/gcc/config/riscv/sync-ztso.md
index 9bdd9e291d9..154ff1a91af 100644
--- a/gcc/config/riscv/sync-ztso.md
+++ b/gcc/config/riscv/sync-ztso.md
@@ -43,7 +43,7 @@ (define_insn "mem_thread_fence_ztso"
(define_insn "atomic_load_ztso<mode>"
[(set (match_operand:ANYI 0 "register_operand" "=r")
(unspec_volatile:ANYI
- [(match_operand:ANYI 1 "memory_operand" "A")
+ [(match_operand:ANYI 1 "memory_operand" "m")
(match_operand:SI 2 "const_int_operand")] ;; model
UNSPECV_ATOMIC_LOAD))]
"TARGET_ZTSO"
@@ -64,12 +64,35 @@ (define_insn "atomic_load_ztso<mode>"
(symbol_ref "(is_mm_seq_cst (memmodel_from_int (INTVAL (operands[2])))
? 8
: 4)"))])
+(define_insn "atomic_load_ztso<X:mode><SUBX:mode><code>"
+ [(set (match_operand:X 0 "register_operand" "=r")
+ (any_extend:X
+ (unspec_volatile:SUBX
+ [(match_operand:SUBX 1 "memory_operand" "m")
+ (match_operand:SUBX 2 "const_int_operand")]
+ UNSPECV_ATOMIC_LOAD)))]
+ "TARGET_ZTSO"
+ {
+ enum memmodel model = (enum memmodel) INTVAL (operands[2]);
+ model = memmodel_base (model);
+
+ if (model == MEMMODEL_SEQ_CST)
+ return "fence\trw,rw\;"
+ "<SUBX:load><u>\t%0,%1";
+ else
+ return "<SUBX:load><u>\t%0,%1";
+ }
+ [(set_attr "type" "multi")
+ (set (attr "length")
+ (symbol_ref "(is_mm_seq_cst (memmodel_from_int (INTVAL (operands[2])))
? 8
+ : 4)"))])
+
(define_insn "atomic_store_ztso<mode>"
- [(set (match_operand:ANYI 0 "memory_operand" "=A")
+ [(set (match_operand:ANYI 0 "memory_operand" "=m,A")
(unspec_volatile:ANYI
- [(match_operand:ANYI 1 "reg_or_0_operand" "rJ")
- (match_operand:SI 2 "const_int_operand")] ;; model
+ [(match_operand:ANYI 1 "reg_or_0_operand" "rJ,rJ")
+ (match_operand:SI 2 "const_int_operand" "B4,B3")] ;; model
UNSPECV_ATOMIC_STORE))]
"TARGET_ZTSO"
{
diff --git a/gcc/testsuite/gcc.target/riscv/load-zalasr.c
b/gcc/testsuite/gcc.target/riscv/load-zalasr.c
new file mode 100644
index 00000000000..10638b8a738
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/load-zalasr.c
@@ -0,0 +1,201 @@
+/* { dg-do compile { target rv64 } } */
+/* { dg-options "-march=rv64gc_zalasr -mabi=lp64d" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Os" "-Og" "-Oz" } } */
+
+
+typedef struct
+{
+ char pad;
+ unsigned char repr;
+} qi_zero_t;
+
+typedef struct
+{
+ char pad;
+ signed char repr;
+} qi_sign_t;
+
+typedef struct
+{
+ short pad;
+ unsigned short repr;
+} hi_zero_t;
+
+typedef struct
+{
+ short pad;
+ short repr;
+} hi_sign_t;
+
+typedef struct
+{
+ int pad;
+ int repr;
+} si_sign_t;
+
+typedef struct
+{
+ int pad;
+ unsigned repr;
+} si_zero_t;
+
+
+
+/*
+**atomic_load_qi_zero:
+** lb [a-z][0-9]+,1\([a-z][0-9]+\)
+** andi [a-z][0-9]+,[a-z][0-9]+,0xff
+** ret
+*/
+unsigned atomic_load_qi_zero (const qi_zero_t *a) {
+ unsigned char r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_qi_sign:
+** lb [a-z][0-9]+,1\([a-z][0-9]+\)
+** ret
+*/
+int atomic_load_qi_sign (const qi_sign_t *a) {
+ signed char r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_hi_zero:
+** lh [a-z][0-9]+,2\([a-z][0-9]+\)
+** slli [a-z][0-9]+,[a-z][0-9]+,48
+** srli [a-z][0-9]+,[a-z][0-9]+,48
+** ret
+*/
+unsigned atomic_load_hi_zero (const hi_zero_t *a) {
+ unsigned short r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_hi_sign:
+** lh [a-z][0-9]+,2\([a-z][0-9]+\)
+** ret
+*/
+int atomic_load_hi_sign (const hi_sign_t *a) {
+ short r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_si_sign:
+** lw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+int atomic_load_si_sign (const si_sign_t *a) {
+ int r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_si_zero:
+** lw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+unsigned atomic_load_si_zero (const si_zero_t *a) {
+ unsigned r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+
+typedef struct
+{
+ int pad;
+ unsigned long long repr;
+} di_t;
+
+typedef struct
+{
+ int pad;
+ unsigned char repr;
+} qi_di_t;
+
+
+/*
+**atomic_load_di:
+** ld [a-z][0-9]+,8\([a-z][0-9]+\)
+** ret
+*/
+unsigned long long atomic_load_di (const di_t *a) {
+ unsigned long long r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_qi_di:
+** lb [a-z][0-9]+,4\([a-z][0-9]+\)
+** andi [a-z][0-9]+,[a-z][0-9]+,0xff
+** ret
+*/
+unsigned long long atomic_load_qi_di (const qi_di_t *a) {
+ unsigned char r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+typedef struct
+{
+ int pad;
+ unsigned repr;
+} t;
+
+
+/*
+**atomic_load_relaxed:
+** lw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+unsigned atomic_load_relaxed (const t *a) {
+ unsigned r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_acquire:
+** addi [a-z][0-9]+,[a-z][0-9]+,4
+** lw.aq [a-z][0-9]+,0\([a-z][0-9]+\)
+** ret
+*/
+unsigned atomic_load_acquire (const t *a) {
+ unsigned r;
+ __atomic_load (&a->repr, &r, __ATOMIC_ACQUIRE);
+ return r;
+}
+
+/*
+**atomic_load_seqcst:
+** fence rw,rw
+** lw [a-z][0-9]+,4\([a-z][0-9]+\)
+** fence r,rw
+** ret
+*/
+unsigned atomic_load_seqcst (const t *a) {
+ unsigned r;
+ __atomic_load (&a->repr, &r, __ATOMIC_SEQ_CST);
+ return r;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/load.c
b/gcc/testsuite/gcc.target/riscv/load.c
new file mode 100644
index 00000000000..8a917888203
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/load.c
@@ -0,0 +1,197 @@
+/* { dg-do compile { target rv64 } } */
+/* { dg-options "-march=rv64gc -mabi=lp64d" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Os" "-Og" "-Oz" } } */
+
+typedef struct
+{
+ char pad;
+ unsigned char repr;
+} qi_zero_t;
+
+typedef struct
+{
+ char pad;
+ signed char repr;
+} qi_sign_t;
+
+typedef struct
+{
+ short pad;
+ unsigned short repr;
+} hi_zero_t;
+
+typedef struct
+{
+ short pad;
+ short repr;
+} hi_sign_t;
+
+typedef struct
+{
+ int pad;
+ int repr;
+} si_sign_t;
+
+typedef struct
+{
+ int pad;
+ unsigned repr;
+} si_zero_t;
+
+
+
+/*
+**atomic_load_qi_zero:
+** lbu [a-z][0-9]+,1\([a-z][0-9]+\)
+** ret
+*/
+unsigned atomic_load_qi_zero (const qi_zero_t *a) {
+ unsigned char r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_qi_sign:
+** lb [a-z][0-9]+,1\([a-z][0-9]+\)
+** ret
+*/
+int atomic_load_qi_sign (const qi_sign_t *a) {
+ signed char r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_hi_zero:
+** lhu [a-z][0-9]+,2\([a-z][0-9]+\)
+** ret
+*/
+unsigned atomic_load_hi_zero (const hi_zero_t *a) {
+ unsigned short r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_hi_sign:
+** lh [a-z][0-9]+,2\([a-z][0-9]+\)
+** ret
+*/
+int atomic_load_hi_sign (const hi_sign_t *a) {
+ short r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_si_sign:
+** lw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+int atomic_load_si_sign (const si_sign_t *a) {
+ int r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_si_zero:
+** lw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+unsigned atomic_load_si_zero (const si_zero_t *a) {
+ unsigned r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+
+typedef struct
+{
+ int pad;
+ unsigned long long repr;
+} di_t;
+
+typedef struct
+{
+ int pad;
+ unsigned char repr;
+} qi_di_t;
+
+
+/*
+**atomic_load_di:
+** ld [a-z][0-9]+,8\([a-z][0-9]+\)
+** ret
+*/
+unsigned long long atomic_load_di (const di_t *a) {
+ unsigned long long r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_qi_di:
+** lbu [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+unsigned long long atomic_load_qi_di (const qi_di_t *a) {
+ unsigned char r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+typedef struct
+{
+ int pad;
+ unsigned repr;
+} t;
+
+
+/*
+**atomic_load_relaxed:
+** lw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+unsigned atomic_load_relaxed (const t *a) {
+ unsigned r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_acquire:
+** lw [a-z][0-9]+,4\([a-z][0-9]+\)
+** fence r,rw
+** ret
+*/
+unsigned atomic_load_acquire (const t *a) {
+ unsigned r;
+ __atomic_load (&a->repr, &r, __ATOMIC_ACQUIRE);
+ return r;
+}
+
+
+/*
+**atomic_load_seqcst:
+** fence rw,rw
+** lw [a-z][0-9]+,4\([a-z][0-9]+\)
+** fence r,rw
+** ret
+*/
+unsigned atomic_load_seqcst (const t *a) {
+ unsigned r;
+ __atomic_load (&a->repr, &r, __ATOMIC_SEQ_CST);
+ return r;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/load32-zalasr.c
b/gcc/testsuite/gcc.target/riscv/load32-zalasr.c
new file mode 100644
index 00000000000..9a3756fb66a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/load32-zalasr.c
@@ -0,0 +1,161 @@
+/* { dg-do compile { target rv32 } } */
+/* { dg-options "-march=rv32gc_zalasr -mabi=ilp32" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" } } */
+
+typedef struct
+{
+ char pad;
+ unsigned char repr;
+} qi_zero_t;
+
+typedef struct
+{
+ char pad;
+ signed char repr;
+} qi_sign_t;
+
+typedef struct
+{
+ short pad;
+ unsigned short repr;
+} hi_zero_t;
+
+typedef struct
+{
+ short pad;
+ short repr;
+} hi_sign_t;
+
+typedef struct
+{
+ int pad;
+ int repr;
+} si_sign_t;
+
+typedef struct
+{
+ int pad;
+ unsigned repr;
+} si_zero_t;
+
+
+/*
+**atomic_load_qi_zero:
+** lb [a-z][0-9]+,1\([a-z][0-9]+\)
+** andi [a-z][0-9]+,[a-z][0-9]+,0xff
+** ret
+*/
+unsigned atomic_load_qi_zero (const qi_zero_t *a) {
+ unsigned char r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_qi_sign:
+** lb [a-z][0-9]+,1\([a-z][0-9]+\)
+** ret
+*/
+int atomic_load_qi_sign (const qi_sign_t *a) {
+ signed char r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_hi_zero:
+** lh [a-z][0-9]+,2\([a-z][0-9]+\)
+** slli [a-z][0-9]+,[a-z][0-9]+,16
+** srli [a-z][0-9]+,[a-z][0-9]+,16
+** ret
+*/
+unsigned atomic_load_hi_zero (const hi_zero_t *a) {
+ unsigned short r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_hi_sign:
+** lh [a-z][0-9]+,2\([a-z][0-9]+\)
+** ret
+*/
+int atomic_load_hi_sign (const hi_sign_t *a) {
+ short r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_si_sign:
+** lw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+int atomic_load_si_sign (const si_sign_t *a) {
+ int r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_si_zero:
+** lw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+unsigned atomic_load_si_zero (const si_zero_t *a) {
+ unsigned r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+typedef struct
+{
+ int pad;
+ unsigned repr;
+} t;
+
+
+/*
+**atomic_load_relaxed:
+** lw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+unsigned atomic_load_relaxed (const t *a) {
+ unsigned r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_acquire:
+** addi [a-z][0-9]+,[a-z][0-9]+,4
+** lw.aq [a-z][0-9]+,0\([a-z][0-9]+\)
+** ret
+*/
+unsigned atomic_load_acquire (const t *a) {
+ unsigned r;
+ __atomic_load (&a->repr, &r, __ATOMIC_ACQUIRE);
+ return r;
+}
+
+
+/*
+**atomic_load_seqcst:
+** fence rw,rw
+** lw [a-z][0-9]+,4\([a-z][0-9]+\)
+** fence r,rw
+** ret
+*/
+unsigned atomic_load_seqcst (const t *a) {
+ unsigned r;
+ __atomic_load (&a->repr, &r, __ATOMIC_SEQ_CST);
+ return r;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/load32.c
b/gcc/testsuite/gcc.target/riscv/load32.c
new file mode 100644
index 00000000000..a0729ffd3cd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/load32.c
@@ -0,0 +1,157 @@
+/* { dg-do compile { target rv32 } } */
+/* { dg-options "-march=rv32gc -mabi=ilp32" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Og" "-Oz" } } */
+typedef struct
+{
+ char pad;
+ unsigned char repr;
+} qi_zero_t;
+
+typedef struct
+{
+ char pad;
+ signed char repr;
+} qi_sign_t;
+
+typedef struct
+{
+ short pad;
+ unsigned short repr;
+} hi_zero_t;
+
+typedef struct
+{
+ short pad;
+ short repr;
+} hi_sign_t;
+
+typedef struct
+{
+ int pad;
+ int repr;
+} si_sign_t;
+
+typedef struct
+{
+ int pad;
+ unsigned repr;
+} si_zero_t;
+
+
+/*
+**atomic_load_qi_zero:
+** lbu [a-z][0-9]+,1\([a-z][0-9]+\)
+** ret
+*/
+unsigned atomic_load_qi_zero (const qi_zero_t *a) {
+ unsigned char r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_qi_sign:
+** lb [a-z][0-9]+,1\([a-z][0-9]+\)
+** ret
+*/
+int atomic_load_qi_sign (const qi_sign_t *a) {
+ signed char r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_hi_zero:
+** lhu [a-z][0-9]+,2\([a-z][0-9]+\)
+** ret
+*/
+unsigned atomic_load_hi_zero (const hi_zero_t *a) {
+ unsigned short r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_hi_sign:
+** lh [a-z][0-9]+,2\([a-z][0-9]+\)
+** ret
+*/
+int atomic_load_hi_sign (const hi_sign_t *a) {
+ short r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_si_sign:
+** lw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+int atomic_load_si_sign (const si_sign_t *a) {
+ int r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_si_zero:
+** lw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+unsigned atomic_load_si_zero (const si_zero_t *a) {
+ unsigned r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+typedef struct
+{
+ int pad;
+ unsigned repr;
+} t;
+
+
+/*
+**atomic_load_relaxed:
+** lw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+unsigned atomic_load_relaxed (const t *a) {
+ unsigned r;
+ __atomic_load (&a->repr, &r, __ATOMIC_RELAXED);
+ return r;
+}
+
+
+/*
+**atomic_load_acquire:
+** lw [a-z][0-9]+,4\([a-z][0-9]+\)
+** fence r,rw
+** ret
+*/
+unsigned atomic_load_acquire (const t *a) {
+ unsigned r;
+ __atomic_load (&a->repr, &r, __ATOMIC_ACQUIRE);
+ return r;
+}
+
+
+/*
+**atomic_load_seqcst:
+** fence rw,rw
+** lw [a-z][0-9]+,4\([a-z][0-9]+\)
+** fence r,rw
+** ret
+*/
+unsigned atomic_load_seqcst (const t *a) {
+ unsigned r;
+ __atomic_load (&a->repr, &r, __ATOMIC_SEQ_CST);
+ return r;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/store-zalasr.c
b/gcc/testsuite/gcc.target/riscv/store-zalasr.c
new file mode 100644
index 00000000000..d2f5f010375
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/store-zalasr.c
@@ -0,0 +1,122 @@
+/* { dg-do compile { target rv64 } } */
+/* { dg-options "-march=rv64gc_zalasr -mabi=lp64d" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" } } */
+
+typedef struct
+{
+ char pad;
+ unsigned char repr;
+} qi_s_t;
+
+typedef struct
+{
+ short pad;
+ unsigned short repr;
+} hi_s_t;
+
+typedef struct
+{
+ int pad;
+ unsigned repr;
+} si_s_t;
+
+
+/*
+**atomic_store_qi:
+** sb [a-z][0-9]+,1\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_qi (qi_s_t *a, unsigned char val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELAXED);
+}
+
+
+/*
+**atomic_store_hi:
+** sh [a-z][0-9]+,2\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_hi (hi_s_t *a, unsigned short val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELAXED);
+}
+
+
+/*
+**atomic_store_si:
+** sw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_si (si_s_t *a, unsigned val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELAXED);
+}
+
+
+typedef struct
+{
+ int pad;
+ unsigned long long repr;
+} di_s_t;
+
+
+/*
+**atomic_store_di:
+** sd [a-z][0-9]+,8\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_di (di_s_t *a, unsigned long long val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELAXED);
+}
+
+
+typedef struct
+{
+ int pad;
+ unsigned repr;
+} s_mm;
+
+
+/*
+**atomic_store_relaxed:
+** sw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_relaxed (s_mm *a, unsigned val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELAXED);
+}
+
+
+/*
+**atomic_store_release:
+** addi [a-z][0-9]+,[a-z][0-9]+,4
+** sw.rl [a-z][0-9]+,0\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_release (s_mm *a, unsigned val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELEASE);
+}
+
+
+/*
+**atomic_store_seqcst:
+** addi [a-z][0-9]+,[a-z][0-9]+,4
+** sw.rl [a-z][0-9]+,0\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_seqcst (s_mm *a, unsigned val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_SEQ_CST);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/store.c
b/gcc/testsuite/gcc.target/riscv/store.c
new file mode 100644
index 00000000000..d71756e9268
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/store.c
@@ -0,0 +1,122 @@
+/* { dg-do compile { target rv64 } } */
+/* { dg-options "-march=rv64gc -mabi=lp64d" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" } } */
+typedef struct
+{
+ char pad;
+ unsigned char repr;
+} qi_s_t;
+
+typedef struct
+{
+ short pad;
+ unsigned short repr;
+} hi_s_t;
+
+typedef struct
+{
+ int pad;
+ unsigned repr;
+} si_s_t;
+
+
+/*
+**atomic_store_qi:
+** sb [a-z][0-9]+,1\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_qi (qi_s_t *a, unsigned char val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELAXED);
+}
+
+
+/*
+**atomic_store_hi:
+** sh [a-z][0-9]+,2\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_hi (hi_s_t *a, unsigned short val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELAXED);
+}
+
+
+/*
+**atomic_store_si:
+** sw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_si (si_s_t *a, unsigned val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELAXED);
+}
+
+
+typedef struct
+{
+ int pad;
+ unsigned long long repr;
+} di_s_t;
+
+
+/*
+**atomic_store_di:
+** sd [a-z][0-9]+,8\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_di (di_s_t *a, unsigned long long val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELAXED);
+}
+
+
+typedef struct
+{
+ int pad;
+ unsigned repr;
+} s_mm;
+
+
+/*
+**atomic_store_relaxed:
+** sw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_relaxed (s_mm *a, unsigned val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELAXED);
+}
+
+
+/*
+**atomic_store_release:
+** fence rw,w
+** sw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_release (s_mm *a, unsigned val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELEASE);
+}
+
+
+/*
+**atomic_store_seqcst:
+** fence rw,w
+** sw [a-z][0-9]+,4\([a-z][0-9]+\)
+** fence rw,rw
+** ret
+*/
+void
+atomic_store_seqcst (s_mm *a, unsigned val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_SEQ_CST);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/store32-zalasr.c
b/gcc/testsuite/gcc.target/riscv/store32-zalasr.c
new file mode 100644
index 00000000000..d4e37e7169f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/store32-zalasr.c
@@ -0,0 +1,105 @@
+/* { dg-do compile { target rv32 } } */
+/* { dg-options "-march=rv32gc_zalasr -mabi=ilp32" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" } } */
+
+typedef struct
+{
+ char pad;
+ unsigned char repr;
+} qi_s_t;
+
+typedef struct
+{
+ short pad;
+ unsigned short repr;
+} hi_s_t;
+
+typedef struct
+{
+ int pad;
+ unsigned repr;
+} si_s_t;
+
+
+/*
+**atomic_store_qi:
+** sb [a-z][0-9]+,1\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_qi (qi_s_t *a, unsigned char val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELAXED);
+}
+
+
+/*
+**atomic_store_hi:
+** sh [a-z][0-9]+,2\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_hi (hi_s_t *a, unsigned short val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELAXED);
+}
+
+
+/*
+**atomic_store_si:
+** sw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_si (si_s_t *a, unsigned val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELAXED);
+}
+
+
+
+
+typedef struct
+{
+ int pad;
+ unsigned repr;
+} s_mm;
+
+
+/*
+**atomic_store_relaxed:
+** sw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_relaxed (s_mm *a, unsigned val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELAXED);
+}
+
+
+/*
+**atomic_store_release:
+** addi [a-z][0-9]+,[a-z][0-9]+,4
+** sw.rl [a-z][0-9]+,0\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_release (s_mm *a, unsigned val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELEASE);
+}
+
+
+/*
+**atomic_store_seqcst:
+** addi [a-z][0-9]+,[a-z][0-9]+,4
+** sw.rl [a-z][0-9]+,0\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_seqcst (s_mm *a, unsigned val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_SEQ_CST);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/store32.c
b/gcc/testsuite/gcc.target/riscv/store32.c
new file mode 100644
index 00000000000..7818852f909
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/store32.c
@@ -0,0 +1,106 @@
+/* { dg-do compile { target rv32 } } */
+/* { dg-options "-march=rv32gc -mabi=ilp32" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" "-Oz" } } */
+
+typedef struct
+{
+ char pad;
+ unsigned char repr;
+} qi_s_t;
+
+typedef struct
+{
+ short pad;
+ unsigned short repr;
+} hi_s_t;
+
+typedef struct
+{
+ int pad;
+ unsigned repr;
+} si_s_t;
+
+
+/*
+**atomic_store_qi:
+** sb [a-z][0-9]+,1\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_qi (qi_s_t *a, unsigned char val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELAXED);
+}
+
+
+/*
+**atomic_store_hi:
+** sh [a-z][0-9]+,2\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_hi (hi_s_t *a, unsigned short val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELAXED);
+}
+
+
+/*
+**atomic_store_si:
+** sw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_si (si_s_t *a, unsigned val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELAXED);
+}
+
+
+
+
+typedef struct
+{
+ int pad;
+ unsigned repr;
+} s_mm;
+
+
+/*
+**atomic_store_relaxed:
+** sw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_relaxed (s_mm *a, unsigned val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELAXED);
+}
+
+
+/*
+**atomic_store_release:
+** fence rw,w
+** sw [a-z][0-9]+,4\([a-z][0-9]+\)
+** ret
+*/
+void
+atomic_store_release (s_mm *a, unsigned val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_RELEASE);
+}
+
+
+/*
+**atomic_store_seqcst:
+** fence rw,w
+** sw [a-z][0-9]+,4\([a-z][0-9]+\)
+** fence rw,rw
+** ret
+*/
+void
+atomic_store_seqcst (s_mm *a, unsigned val)
+{
+ __atomic_store (&a->repr, &val, __ATOMIC_SEQ_CST);
+}