RVWMO and Ztso are alternative RISC-V memory models. They are mutually exclusive: a target uses either the default RVWMO model or Ztso. Zalasr is an independent extension that can be enabled on top of either model.

The same C11 atomics therefore have four possible target configurations.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdatomic.h>

int load_acquire(_Atomic int *p) {
return atomic_load_explicit(p, memory_order_acquire);
}

void thread_load_fence(void) {
atomic_thread_fence(memory_order_acquire);
}

void store_release(_Atomic int *p, int v) {
atomic_store_explicit(p, v, memory_order_release);
}

void thread_store_fence(void) {
atomic_thread_fence(memory_order_release);
}

void store_seq_cst(_Atomic int *p, int v) {
atomic_store_explicit(p, v, memory_order_seq_cst);
}

The generated ordering instructions can be compared as follows:

Operation RVWMO RVWMO + Zalasr Ztso Ztso + Zalasr
Acquire load lw + fence r,rw lw.aq lw lw
Acquire fence fence r,rw fence r,rw none none
Release store fence rw,w + sw sw.rl sw sw
Release fence fence rw,w fence rw,w none none
Sequentially consistent store fence rw,w + sw + fence rw,rw sw.rl sw + fence rw,rw sw.rl

RVWMO (baseline, -O2 -march=rv64g)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
load_acquire:
lw a0,0(a0)
fence r,rw
ret
thread_load_fence:
fence r,rw
ret
store_release:
fence rw,w
sw a1,0(a0)
ret
thread_store_fence:
fence rw,w
ret
store_seq_cst:
fence rw,w
sw a1,0(a0)
fence rw,rw
ret

RVWMO + Zalasr (-O2 -march=rv64g_zalasr)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
load_acquire:
lw.aq a0,0(a0)
ret
thread_load_fence:
fence r,rw
ret
store_release:
sw.rl a1,0(a0)
ret
thread_store_fence:
fence rw,w
ret
store_seq_cst:
sw.rl a1,0(a0)
ret

Ztso (-O2 -march=rv64g_ztso)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
load_acquire:
lw a0,0(a0)
ret
thread_load_fence:
ret
store_release:
sw a1,0(a0)
ret
thread_store_fence:
ret
store_seq_cst:
sw a1,0(a0)
fence rw,rw
ret

Ztso + Zalasr (-O2 -march=rv64g_ztso_zalasr)

1
2
3
4
5
6
7
8
9
10
11
12
13
load_acquire:
lw a0,0(a0)
ret
thread_load_fence:
ret
store_release:
sw a1,0(a0)
ret
thread_store_fence:
ret
store_seq_cst:
sw.rl a1,0(a0)
ret

Ztso already provides the ordering needed by acquire and release operations, so those operations and fences can be emitted without extra ordering instructions. A sequentially consistent store still uses the .rl annotation in this output.