Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What, exactly, does the reservation set size (Za64rs/Za128rs) constrain? #79

Closed
sorear opened this issue Nov 5, 2022 · 2 comments
Closed

Comments

@sorear
Copy link

sorear commented Nov 5, 2022

A simple single-hart platform (among more exotic possibilities) would naturally provide atomicity across the entire address space for LR/SC pairs, regardless of addresses. In such a situation the natural size for the reservation set in the unprivileged ISA is the entire address space, but this is forbidden in RVA20 and RVA22. This is a strange requirement that software does not seem to be able to use beneficially in any reliable way.

What is such an implementation expected to do to be conformant with Za64rs? Force LR/SC instructions which are misaligned across a 64B boundary to trap and force SCs which do not reference the same 64B unit to fail?

What does software gain from a guarantee that LR will fail across 64B boundaries? There is no clear benefit to the memory model since a nonstandard extension accessing multiple 64B units is not forbidden.

What does software gain from a guarantee that SC will fail if it is not paired with a LR on the same 64B unit? Is it trying to prevent a storage channel (even though we require software to clear the reservation on context switches)? A property that constrained LR/SC loops operating on different 64B blocks will experience individual, rather than collective, eventual success (even though there is nothing to support this in the ISA manual's description of LR/SC eventuality)?

@aswaterman
Copy link
Member

IIRC, the motivation was simply that, since the reservation set size is architecturally visible, it should be given a name, as we are trying to do for other architecturally visible properties.

Yes, the implication for implementations is that LR followed by SC to a different reservation set must fail. We aren't claiming that software can usefully take advantage of the guaranteed-failure property--but it is a visible property nonetheless.

There's also a performance justification to making the reservation set size known: on many implementations, LR/SC success probability will increase if contended synchronization variables are placed in different reservation sets. Even though this doesn't strengthen any architectural guarantees, it's still something that some software will want to be aware of in practice. And in some cases (e.g. https://github.com/torvalds/linux/blob/8395ae05cb5a2e31d36106e8c85efa11cda849be/arch/riscv/include/asm/cache.h#L12) the size can only be taken advantage of if it is statically known.

@kasanovic
Copy link
Collaborator

In the presence of virtual memory, it is already required than an SC fail if it is to a different page in memory (sec 5.3.1 in current priv arch document), so a simple implementation cannot reserve all of memory.

Given this requirement, there is little additional cost for single-hart RVA systems to fail SC outside of the 64-byte res. set, and this removes one small incompatibility. The advantage to software is the limit to the padding inserted between contended synchronization variables.

compiler-errors added a commit to compiler-errors/rust that referenced this issue Feb 25, 2025
rustc_target: Add more RISC-V atomic-related features

This is a continuation of rust-lang#130877 and adds a few target features, including `zacas`, which was experimental in LLVM 19 and marked non-experimental in LLVM 20.

This adds the following target features to unstable riscv_target_feature:

- `za64rs` (Za64rs Extension 1.0): Reservation Set Size of at Most 64 Bytes
  ([definition in LLVM](https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0-rc2/llvm/lib/Target/RISCV/RISCVFeatures.td#L227-L228), [available since LLVM 18](llvm/llvm-project@8649328))
- `za128rs` (Za128rs Extension 1.0): Reservation Set Size of at Most 128 Bytes
  ([definition in LLVM](https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0-rc2/llvm/lib/Target/RISCV/RISCVFeatures.td#L230-L231), [available since LLVM 18](llvm/llvm-project@8649328))
  - IIUC, `za*rs` can be referenced when implementing helpers to reduce contention in synchronization primitives, like [`crossbeam_utils::CachePadded`](https://docs.rs/crossbeam-utils/latest/crossbeam_utils/struct.CachePadded.html). (relevant discussion: riscv/riscv-profiles#79)
- `zacas` (Zacas Extension 1.0): Atomic Compare-And-Swap Instructions (`amocas.{w,d,q}{,.aq,.rl,.aqrl}` and `amocas.{b,h}{,.aq,.rl,.aqrl}` when `zabha` is also enabled)
  ([definition in LLVM](https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0-rc2/llvm/lib/Target/RISCV/RISCVFeatures.td#L240-L243), [available as non-experimental since LLVM 20](llvm/llvm-project@614aeda))
  - This implies `zaamo`.
  - This is used to optimize CAS in existing atomics and/or implement 64-bit/128-bit atomics on riscv32/riscv64 (e.g., taiki-e/portable-atomic#173).
  - Note that [LLVM does not automatically use this instruction for 64-bit/128-bit atomics on riscv32/riscv64 even if this feature is enabled, because doing it changes the ABI](https://github.com/llvm/llvm-project/blob/876174ffd7533dc220f94721173bb767b659fa7f/llvm/docs/RISCVUsage.rst#riscv-zacas-note). (If the ability to do that is provided by LLVM in the future, it should probably be controlled by another ABI feature similar to `forced-atomics`.)
- `zama16b` (Zama16b Extension 1.0): Atomic 16-byte misaligned loads, stores and AMOs
  ([definition in LLVM](https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0-rc2/llvm/lib/Target/RISCV/RISCVFeatures.td#L255-L256), [available since LLVM 19](llvm/llvm-project@b090569))
  - IIUC, unlike AArch64 FEAT_LSE2 which also makes 16-byte aligned ldp ({i,u}128 load) atomic, this extension only affects instructions that already considered atomic if they were naturally aligned. i.e., fld (f64 load) on riscv32 would not be atomic with or without this extension ([relevant QEMU code](https://github.com/qemu/qemu/blob/b69801dd6b1eb4d107f7c2f643adf0a4e3ec9124/target/riscv/insn_trans/trans_rvd.c.inc#L50-L62)).
- `zawrs` (Zawrs Extension 1.0): Wait on Reservation Set (`wrs.nto` and `wrs.sto`)
  ([definition in LLVM](https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0-rc2/llvm/lib/Target/RISCV/RISCVFeatures.td#L258), [available as non-experimental since LLVM 17](llvm/llvm-project@d41a73a))
  - This is used to optimize synchronization primitives (e.g., Linux uses this for spinlocks (torvalds/linux@b8ddb0d)).

Btw, the question of whether `zaamo` is implied by `zabha` or not, which was discussed in rust-lang#130877, has been resolved in LLVM 20, since LLVM now treats `zaamo` as implied by `zabha`/`zacas` (llvm/llvm-project#115694), just like GCC and rustc.

r? `@Amanieu`

`@rustbot` label +O-riscv +A-target-feature
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Feb 25, 2025
Rollup merge of rust-lang#137417 - taiki-e:riscv-atomic, r=Amanieu

rustc_target: Add more RISC-V atomic-related features

This is a continuation of rust-lang#130877 and adds a few target features, including `zacas`, which was experimental in LLVM 19 and marked non-experimental in LLVM 20.

This adds the following target features to unstable riscv_target_feature:

- `za64rs` (Za64rs Extension 1.0): Reservation Set Size of at Most 64 Bytes
  ([definition in LLVM](https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0-rc2/llvm/lib/Target/RISCV/RISCVFeatures.td#L227-L228), [available since LLVM 18](llvm/llvm-project@8649328))
- `za128rs` (Za128rs Extension 1.0): Reservation Set Size of at Most 128 Bytes
  ([definition in LLVM](https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0-rc2/llvm/lib/Target/RISCV/RISCVFeatures.td#L230-L231), [available since LLVM 18](llvm/llvm-project@8649328))
  - IIUC, `za*rs` can be referenced when implementing helpers to reduce contention in synchronization primitives, like [`crossbeam_utils::CachePadded`](https://docs.rs/crossbeam-utils/latest/crossbeam_utils/struct.CachePadded.html). (relevant discussion: riscv/riscv-profiles#79)
- `zacas` (Zacas Extension 1.0): Atomic Compare-And-Swap Instructions (`amocas.{w,d,q}{,.aq,.rl,.aqrl}` and `amocas.{b,h}{,.aq,.rl,.aqrl}` when `zabha` is also enabled)
  ([definition in LLVM](https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0-rc2/llvm/lib/Target/RISCV/RISCVFeatures.td#L240-L243), [available as non-experimental since LLVM 20](llvm/llvm-project@614aeda))
  - This implies `zaamo`.
  - This is used to optimize CAS in existing atomics and/or implement 64-bit/128-bit atomics on riscv32/riscv64 (e.g., taiki-e/portable-atomic#173).
  - Note that [LLVM does not automatically use this instruction for 64-bit/128-bit atomics on riscv32/riscv64 even if this feature is enabled, because doing it changes the ABI](https://github.com/llvm/llvm-project/blob/876174ffd7533dc220f94721173bb767b659fa7f/llvm/docs/RISCVUsage.rst#riscv-zacas-note). (If the ability to do that is provided by LLVM in the future, it should probably be controlled by another ABI feature similar to `forced-atomics`.)
- `zama16b` (Zama16b Extension 1.0): Atomic 16-byte misaligned loads, stores and AMOs
  ([definition in LLVM](https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0-rc2/llvm/lib/Target/RISCV/RISCVFeatures.td#L255-L256), [available since LLVM 19](llvm/llvm-project@b090569))
  - IIUC, unlike AArch64 FEAT_LSE2 which also makes 16-byte aligned ldp ({i,u}128 load) atomic, this extension only affects instructions that already considered atomic if they were naturally aligned. i.e., fld (f64 load) on riscv32 would not be atomic with or without this extension ([relevant QEMU code](https://github.com/qemu/qemu/blob/b69801dd6b1eb4d107f7c2f643adf0a4e3ec9124/target/riscv/insn_trans/trans_rvd.c.inc#L50-L62)).
- `zawrs` (Zawrs Extension 1.0): Wait on Reservation Set (`wrs.nto` and `wrs.sto`)
  ([definition in LLVM](https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0-rc2/llvm/lib/Target/RISCV/RISCVFeatures.td#L258), [available as non-experimental since LLVM 17](llvm/llvm-project@d41a73a))
  - This is used to optimize synchronization primitives (e.g., Linux uses this for spinlocks (torvalds/linux@b8ddb0d)).

Btw, the question of whether `zaamo` is implied by `zabha` or not, which was discussed in rust-lang#130877, has been resolved in LLVM 20, since LLVM now treats `zaamo` as implied by `zabha`/`zacas` (llvm/llvm-project#115694), just like GCC and rustc.

r? `@Amanieu`

`@rustbot` label +O-riscv +A-target-feature
RalfJung pushed a commit to RalfJung/miri that referenced this issue Feb 25, 2025
rustc_target: Add more RISC-V atomic-related features

This is a continuation of rust-lang/rust#130877 and adds a few target features, including `zacas`, which was experimental in LLVM 19 and marked non-experimental in LLVM 20.

This adds the following target features to unstable riscv_target_feature:

- `za64rs` (Za64rs Extension 1.0): Reservation Set Size of at Most 64 Bytes
  ([definition in LLVM](https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0-rc2/llvm/lib/Target/RISCV/RISCVFeatures.td#L227-L228), [available since LLVM 18](llvm/llvm-project@8649328))
- `za128rs` (Za128rs Extension 1.0): Reservation Set Size of at Most 128 Bytes
  ([definition in LLVM](https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0-rc2/llvm/lib/Target/RISCV/RISCVFeatures.td#L230-L231), [available since LLVM 18](llvm/llvm-project@8649328))
  - IIUC, `za*rs` can be referenced when implementing helpers to reduce contention in synchronization primitives, like [`crossbeam_utils::CachePadded`](https://docs.rs/crossbeam-utils/latest/crossbeam_utils/struct.CachePadded.html). (relevant discussion: riscv/riscv-profiles#79)
- `zacas` (Zacas Extension 1.0): Atomic Compare-And-Swap Instructions (`amocas.{w,d,q}{,.aq,.rl,.aqrl}` and `amocas.{b,h}{,.aq,.rl,.aqrl}` when `zabha` is also enabled)
  ([definition in LLVM](https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0-rc2/llvm/lib/Target/RISCV/RISCVFeatures.td#L240-L243), [available as non-experimental since LLVM 20](llvm/llvm-project@614aeda))
  - This implies `zaamo`.
  - This is used to optimize CAS in existing atomics and/or implement 64-bit/128-bit atomics on riscv32/riscv64 (e.g., taiki-e/portable-atomic#173).
  - Note that [LLVM does not automatically use this instruction for 64-bit/128-bit atomics on riscv32/riscv64 even if this feature is enabled, because doing it changes the ABI](https://github.com/llvm/llvm-project/blob/876174ffd7533dc220f94721173bb767b659fa7f/llvm/docs/RISCVUsage.rst#riscv-zacas-note). (If the ability to do that is provided by LLVM in the future, it should probably be controlled by another ABI feature similar to `forced-atomics`.)
- `zama16b` (Zama16b Extension 1.0): Atomic 16-byte misaligned loads, stores and AMOs
  ([definition in LLVM](https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0-rc2/llvm/lib/Target/RISCV/RISCVFeatures.td#L255-L256), [available since LLVM 19](llvm/llvm-project@b090569))
  - IIUC, unlike AArch64 FEAT_LSE2 which also makes 16-byte aligned ldp ({i,u}128 load) atomic, this extension only affects instructions that already considered atomic if they were naturally aligned. i.e., fld (f64 load) on riscv32 would not be atomic with or without this extension ([relevant QEMU code](https://github.com/qemu/qemu/blob/b69801dd6b1eb4d107f7c2f643adf0a4e3ec9124/target/riscv/insn_trans/trans_rvd.c.inc#L50-L62)).
- `zawrs` (Zawrs Extension 1.0): Wait on Reservation Set (`wrs.nto` and `wrs.sto`)
  ([definition in LLVM](https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0-rc2/llvm/lib/Target/RISCV/RISCVFeatures.td#L258), [available as non-experimental since LLVM 17](llvm/llvm-project@d41a73a))
  - This is used to optimize synchronization primitives (e.g., Linux uses this for spinlocks (torvalds/linux@b8ddb0d)).

Btw, the question of whether `zaamo` is implied by `zabha` or not, which was discussed in rust-lang/rust#130877, has been resolved in LLVM 20, since LLVM now treats `zaamo` as implied by `zabha`/`zacas` (llvm/llvm-project#115694), just like GCC and rustc.

r? `@Amanieu`

`@rustbot` label +O-riscv +A-target-feature
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants