Skip to content

Commit

Permalink
Support AtomicF16/AtomicF128 under unstable cfgs
Browse files Browse the repository at this point in the history
  • Loading branch information
taiki-e committed Jan 12, 2025
1 parent 4ff9953 commit 582a915
Show file tree
Hide file tree
Showing 13 changed files with 221 additions and 24 deletions.
2 changes: 1 addition & 1 deletion .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ env:
RUST_BACKTRACE: '1'
RUST_TEST_THREADS: '1'
RUSTDOCFLAGS: -D warnings
RUSTFLAGS: -D warnings
RUSTFLAGS: -D warnings --cfg portable_atomic_unstable_f16 --cfg quickcheck_unstable_f16 --cfg rand_unstable_f16 --cfg portable_atomic_unstable_f128 --cfg quickcheck_unstable_f128 --cfg rand_unstable_f128
RUSTUP_MAX_RETRIES: '10'
PORTABLE_ATOMIC_DENY_WARNINGS: '1'

Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,12 @@ jobs:
# TODO: LLVM bug: Undefined temporary symbol error when building std.
- run: printf 'RELEASE=--release\n' >>"${GITHUB_ENV}"
if: startsWith(matrix.target, 'mips-') || startsWith(matrix.target, 'mipsel-')
# for f16 and f128
# https://github.com/rust-lang/compiler-builtins/blob/compiler_builtins-v0.1.142/configure.rs#L60
- run: printf '%s\n' "RUSTFLAGS=${RUSTFLAGS} --cfg portable_atomic_unstable_f16 --cfg quickcheck_unstable_f16 --cfg rand_unstable_f16" >>"${GITHUB_ENV}"
if: matrix.rust == 'nightly' && !(startsWith(matrix.target, 'arm64ec') || startsWith(matrix.target, 'csky') || startsWith(matrix.target, 'hexagon') || startsWith(matrix.target, 'i586') || startsWith(matrix.target, 'i686') || startsWith(matrix.target, 'loongarch64') || startsWith(matrix.target, 'mips') || startsWith(matrix.target, 'powerpc') || startsWith(matrix.target, 's390x') || startsWith(matrix.target, 'sparc') || startsWith(matrix.target, 'wasm') || contains(matrix.flags, 'codegen-backend=cranelift'))
- run: printf '%s\n' "RUSTFLAGS=${RUSTFLAGS} --cfg portable_atomic_unstable_f128 --cfg quickcheck_unstable_f128 --cfg rand_unstable_f128" >>"${GITHUB_ENV}"
if: matrix.rust == 'nightly' && !(startsWith(matrix.target, 'arm64ec') || startsWith(matrix.target, 'i586') || startsWith(matrix.target, 'i686') || startsWith(matrix.target, 'mips64') || startsWith(matrix.target, 'mipsisa64') || startsWith(matrix.target, 'powerpc-') || startsWith(matrix.target, 'powerpc64-') || startsWith(matrix.target, 'sparc') || contains(matrix.flags, 'codegen-backend=cranelift'))
# for serde
- run: printf '%s\n' "RUSTFLAGS=${RUSTFLAGS} --cfg no_diagnostic_namespace" >>"${GITHUB_ENV}"
if: matrix.rust == 'nightly-2024-02-13'
Expand Down
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Portable atomic types including support for 128-bit atomics, atomic float, etc.
# - env.TEST_FEATURES in .github/workflows/ci.yml.
# - test_features list in tools/build.sh and tools/test.sh.
features = ["float", "std", "serde", "critical-section"]
rustdoc-args = ["--cfg", "portable_atomic_unstable_f16", "--cfg", "portable_atomic_unstable_f128"]
targets = ["x86_64-unknown-linux-gnu"]

[package.metadata.cargo_check_external_types]
Expand Down Expand Up @@ -132,8 +133,8 @@ unexpected_cfgs = { level = "warn", check-cfg = [
# Known custom cfgs, excluding those that may be set by build script.
# Not public API.
'cfg(portable_atomic_test_outline_atomics_detect_false,qemu,valgrind)',
# Public APIs, considered unstable unless documented in readme.
'cfg(portable_atomic_no_outline_atomics,portable_atomic_outline_atomics)',
# Public APIs, considered unstable unless documented as stable in readme.
'cfg(portable_atomic_no_outline_atomics,portable_atomic_outline_atomics,portable_atomic_unstable_f16,portable_atomic_unstable_f128)',
# Public unstable API(s) - portable-atomic-util
'cfg(portable_atomic_unstable_coerce_unsized)',
] }
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Portable atomic types including support for 128-bit atomics, atomic float, etc.
- Provide all atomic integer types (`Atomic{I,U}{8,16,32,64}`) for all targets that can use atomic CAS. (i.e., all targets that can use `std`, and most no-std targets)
- Provide `AtomicI128` and `AtomicU128`.
- Provide `AtomicF32` and `AtomicF64`. ([optional, requires the `float` feature](#optional-features-float))
- Provide `AtomicF16` and `AtomicF128` for [unstable `f16` and `f128`](https://github.com/rust-lang/rust/issues/116909). ([optional, requires the `float` feature and unstable cfgs](#optional-features-float))
- Provide atomic load/store for targets where atomic is not available at all in the standard library. (RISC-V without A-extension, MSP430, AVR)
- Provide atomic CAS for targets where atomic CAS is not available in the standard library. (thumbv6m, pre-v6 Arm, RISC-V without A-extension, MSP430, AVR, Xtensa, etc.) (always enabled for MSP430 and AVR, [optional](#optional-features-critical-section) otherwise)
- Provide stable equivalents of the standard library's atomic types' unstable APIs, such as [`AtomicPtr::fetch_*`](https://github.com/rust-lang/rust/issues/99108).
Expand Down Expand Up @@ -70,7 +71,12 @@ See the [`atomic128` module's readme](https://github.com/taiki-e/portable-atomic
- <a name="optional-features-float"></a>**`float`**<br>
Provide `AtomicF{32,64}`.

Note that most of `fetch_*` operations of atomic floats are implemented using CAS loops, which can be slower than equivalent operations of atomic integers. ([GPU targets have atomic instructions for float, so we plan to use these instructions for GPU targets in the future.](https://github.com/taiki-e/portable-atomic/issues/34))
- When unstable `--cfg portable_atomic_unstable_f16` is also enabled, `AtomicF16` for [unstable `f16`](https://github.com/rust-lang/rust/issues/116909) is also provided.
- When unstable `--cfg portable_atomic_unstable_f128` is also enabled, `AtomicF128` for [unstable `f128`](https://github.com/rust-lang/rust/issues/116909) is also provided.

Note:
- Most of `fetch_*` operations of atomic floats are implemented using CAS loops, which can be slower than equivalent operations of atomic integers. (AArch64 with FEAT_LSFE and GPU targets have atomic instructions for float, [so we plan to use these instructions for them in the future.](https://github.com/taiki-e/portable-atomic/issues/34))
- Unstable cfgs are outside of the normal semver guarantees and minor or patch versions of portable-atomic may make breaking changes to them at any time.

- **`std`**<br>
Use `std`.
Expand Down
8 changes: 8 additions & 0 deletions src/imp/float/int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,17 @@ macro_rules! atomic_float {
};
}

#[cfg(portable_atomic_unstable_f16)]
cfg_has_atomic_16! {
atomic_float!(AtomicF16, f16, AtomicU16, u16, 2);
}
cfg_has_atomic_32! {
atomic_float!(AtomicF32, f32, AtomicU32, u32, 4);
}
cfg_has_atomic_64! {
atomic_float!(AtomicF64, f64, AtomicU64, u64, 8);
}
#[cfg(portable_atomic_unstable_f128)]
cfg_has_atomic_128! {
atomic_float!(AtomicF128, f128, AtomicU128, u128, 16);
}
8 changes: 8 additions & 0 deletions src/imp/float/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,17 @@ Atomic float implementations

mod int;

#[cfg(portable_atomic_unstable_f16)]
cfg_has_atomic_16! {
pub(crate) use self::int::AtomicF16;
}
cfg_has_atomic_32! {
pub(crate) use self::int::AtomicF32;
}
cfg_has_atomic_64! {
pub(crate) use self::int::AtomicF64;
}
#[cfg(portable_atomic_unstable_f128)]
cfg_has_atomic_128! {
pub(crate) use self::int::AtomicF128;
}
29 changes: 20 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Portable atomic types including support for 128-bit atomics, atomic float, etc.
- Provide all atomic integer types (`Atomic{I,U}{8,16,32,64}`) for all targets that can use atomic CAS. (i.e., all targets that can use `std`, and most no-std targets)
- Provide `AtomicI128` and `AtomicU128`.
- Provide `AtomicF32` and `AtomicF64`. ([optional, requires the `float` feature](#optional-features-float))
- Provide `AtomicF16` and `AtomicF128` for [unstable `f16` and `f128`](https://github.com/rust-lang/rust/issues/116909). ([optional, requires the `float` feature and unstable cfgs](#optional-features-float))
- Provide atomic load/store for targets where atomic is not available at all in the standard library. (RISC-V without A-extension, MSP430, AVR)
- Provide atomic CAS for targets where atomic CAS is not available in the standard library. (thumbv6m, pre-v6 Arm, RISC-V without A-extension, MSP430, AVR, Xtensa, etc.) (always enabled for MSP430 and AVR, [optional](#optional-features-critical-section) otherwise)
- Provide stable equivalents of the standard library's atomic types' unstable APIs, such as [`AtomicPtr::fetch_*`](https://github.com/rust-lang/rust/issues/99108).
Expand Down Expand Up @@ -64,7 +65,12 @@ See the [`atomic128` module's readme](https://github.com/taiki-e/portable-atomic
- <a name="optional-features-float"></a>**`float`**<br>
Provide `AtomicF{32,64}`.
Note that most of `fetch_*` operations of atomic floats are implemented using CAS loops, which can be slower than equivalent operations of atomic integers. ([GPU targets have atomic instructions for float, so we plan to use these instructions for GPU targets in the future.](https://github.com/taiki-e/portable-atomic/issues/34))
- When unstable `--cfg portable_atomic_unstable_f16` is also enabled, `AtomicF16` for [unstable `f16`](https://github.com/rust-lang/rust/issues/116909) is also provided.
- When unstable `--cfg portable_atomic_unstable_f128` is also enabled, `AtomicF128` for [unstable `f128`](https://github.com/rust-lang/rust/issues/116909) is also provided.
Note:
- Most of `fetch_*` operations of atomic floats are implemented using CAS loops, which can be slower than equivalent operations of atomic integers. (AArch64 with FEAT_LSFE and GPU targets have atomic instructions for float, [so we plan to use these instructions for them in the future.](https://github.com/taiki-e/portable-atomic/issues/34))
- Unstable cfgs are outside of the normal semver guarantees and minor or patch versions of portable-atomic may make breaking changes to them at any time.
- **`std`**<br>
Use `std`.
Expand Down Expand Up @@ -230,6 +236,10 @@ RUSTFLAGS="--cfg portable_atomic_no_outline_atomics" cargo ...
),
feature(asm_experimental_arch)
)]
// f16/f128
// cfg is unstable and explicitly enabled by the user
#![cfg_attr(portable_atomic_unstable_f16, feature(f16))]
#![cfg_attr(portable_atomic_unstable_f128, feature(f128))]
// Old nightly only
// These features are already stabilized or have already been removed from compilers,
// and can safely be enabled for old nightly as long as version detection works.
Expand Down Expand Up @@ -4115,12 +4125,15 @@ assert_eq!(foo.load(Ordering::Relaxed), 5);
} // cfg_no_atomic_cas!
$(
#[$cfg_float]
atomic_int!(float, $atomic_float_type, $float_type, $atomic_type, $int_type, $align);
atomic_int!(float,
#[$cfg_float] $atomic_float_type, $float_type, $atomic_type, $int_type, $align
);
)?
};

// AtomicF* impls
(float,
#[$cfg_float:meta]
$atomic_type:ident,
$float_type:ident,
$atomic_int_type:ident,
Expand All @@ -4134,7 +4147,7 @@ This type has the same in-memory representation as the underlying floating point
[`", stringify!($float_type), "`].
"
),
#[cfg_attr(docsrs, doc(cfg(feature = "float")))]
#[cfg_attr(docsrs, doc($cfg_float))]
// We can use #[repr(transparent)] here, but #[repr(C, align(N))]
// will show clearer docs.
#[repr(C, align($align))]
Expand Down Expand Up @@ -4754,9 +4767,8 @@ cfg_has_atomic_8! {
}
cfg_has_atomic_16! {
atomic_int!(AtomicI16, i16, 2, cfg_has_atomic_cas_or_amo8, cfg_no_atomic_cas_or_amo8);
atomic_int!(AtomicU16, u16, 2, cfg_has_atomic_cas_or_amo8, cfg_no_atomic_cas_or_amo8);
// TODO: support once https://github.com/rust-lang/rust/issues/116909 stabilized.
// #[cfg(all(feature = "float", not(portable_atomic_no_f16)))] AtomicF16, f16);
atomic_int!(AtomicU16, u16, 2, cfg_has_atomic_cas_or_amo8, cfg_no_atomic_cas_or_amo8,
#[cfg(all(feature = "float", portable_atomic_unstable_f16))] AtomicF16, f16);
}
cfg_has_atomic_32! {
atomic_int!(AtomicI32, i32, 4, cfg_has_atomic_cas_or_amo32, cfg_no_atomic_cas_or_amo32);
Expand All @@ -4770,9 +4782,8 @@ cfg_has_atomic_64! {
}
cfg_has_atomic_128! {
atomic_int!(AtomicI128, i128, 16, cfg_has_atomic_cas_or_amo32, cfg_no_atomic_cas_or_amo32);
atomic_int!(AtomicU128, u128, 16, cfg_has_atomic_cas_or_amo32, cfg_no_atomic_cas_or_amo32);
// TODO: support once https://github.com/rust-lang/rust/issues/116909 stabilized.
// #[cfg(all(feature = "float", not(portable_atomic_no_f128)))] AtomicF128, f128);
atomic_int!(AtomicU128, u128, 16, cfg_has_atomic_cas_or_amo32, cfg_no_atomic_cas_or_amo32,
#[cfg(all(feature = "float", portable_atomic_unstable_f128))] AtomicF128, f128);
}

// See https://github.com/taiki-e/portable-atomic/issues/180
Expand Down
68 changes: 67 additions & 1 deletion src/tests/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,18 @@ macro_rules! __test_atomic_float {
}
#[test]
fn fetch_max() {
if mem::size_of::<$float_type>() == 16
&& cfg!(any(
target_arch = "arm",
target_arch = "mips",
target_arch = "mips32r6",
target_vendor = "apple",
windows,
))
{
// TODO(f128):
return;
}
let a = <$atomic_type>::new(23.);
test_swap_ordering(|order| a.fetch_max(23., order));
for &order in &helper::SWAP_ORDERINGS {
Expand All @@ -1026,6 +1038,18 @@ macro_rules! __test_atomic_float {
}
#[test]
fn fetch_min() {
if mem::size_of::<$float_type>() == 16
&& cfg!(any(
target_arch = "arm",
target_arch = "mips",
target_arch = "mips32r6",
target_vendor = "apple",
windows,
))
{
// TODO(f128):
return;
}
let a = <$atomic_type>::new(23.);
test_swap_ordering(|order| a.fetch_min(23., order));
for &order in &helper::SWAP_ORDERINGS {
Expand Down Expand Up @@ -1071,7 +1095,7 @@ macro_rules! __test_atomic_float {
}
fn quickcheck_compare_exchange(x: $float_type, y: $float_type) -> bool {
let z = loop {
let z = fastrand::$float_type();
let z = float_rand::$float_type();
if z != y {
break z;
}
Expand Down Expand Up @@ -1119,6 +1143,18 @@ macro_rules! __test_atomic_float {
true
}
fn quickcheck_fetch_max(x: $float_type, y: $float_type) -> bool {
if mem::size_of::<$float_type>() == 16
&& cfg!(any(
target_arch = "arm",
target_arch = "mips",
target_arch = "mips32r6",
target_vendor = "apple",
windows,
))
{
// TODO(f128):
return true;
}
for &order in &helper::SWAP_ORDERINGS {
let a = <$atomic_type>::new(x);
assert_float_op_eq!(a.fetch_max(y, order), x);
Expand All @@ -1130,6 +1166,18 @@ macro_rules! __test_atomic_float {
true
}
fn quickcheck_fetch_min(x: $float_type, y: $float_type) -> bool {
if mem::size_of::<$float_type>() == 16
&& cfg!(any(
target_arch = "arm",
target_arch = "mips",
target_arch = "mips32r6",
target_vendor = "apple",
windows,
))
{
// TODO(f128):
return true;
}
for &order in &helper::SWAP_ORDERINGS {
let a = <$atomic_type>::new(x);
assert_float_op_eq!(a.fetch_min(y, order), x);
Expand Down Expand Up @@ -2513,3 +2561,21 @@ macro_rules! stress_test {
}
};
}

#[cfg(feature = "float")]
pub(crate) mod float_rand {
#[cfg(portable_atomic_unstable_f16)]
pub(crate) fn f16() -> f16 {
f16::from_bits(fastrand::u16(..))
}
pub(crate) fn f32() -> f32 {
f32::from_bits(fastrand::u32(..))
}
pub(crate) fn f64() -> f64 {
f64::from_bits(fastrand::u64(..))
}
#[cfg(portable_atomic_unstable_f128)]
pub(crate) fn f128() -> f128 {
f128::from_bits(fastrand::u128(..))
}
}
Loading

0 comments on commit 582a915

Please sign in to comment.