From 582a9156368d9a4e19be0c724d3635efde4d25a2 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sun, 12 Jan 2025 20:58:24 +0900 Subject: [PATCH] Support AtomicF16/AtomicF128 under unstable cfgs --- .cirrus.yml | 2 +- .github/workflows/ci.yml | 6 ++++ Cargo.toml | 5 +-- README.md | 8 ++++- src/imp/float/int.rs | 8 +++++ src/imp/float/mod.rs | 8 +++++ src/lib.rs | 29 ++++++++++----- src/tests/helper.rs | 68 +++++++++++++++++++++++++++++++++++- src/tests/mod.rs | 47 +++++++++++++++++++++++-- src/utils.rs | 26 ++++++++++---- tests/api-test/src/helper.rs | 24 +++++++++++++ tests/api-test/src/lib.rs | 10 ++++++ tools/build.sh | 4 +++ 13 files changed, 221 insertions(+), 24 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index b70ab9a8..2f7a1d79 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -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' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bd7e59e3..69a45432 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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' diff --git a/Cargo.toml b/Cargo.toml index 1037930e..ff86f32e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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] @@ -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)', ] } diff --git a/README.md b/README.md index 329fc876..86fa52d5 100644 --- a/README.md +++ b/README.md @@ -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). @@ -70,7 +71,12 @@ See the [`atomic128` module's readme](https://github.com/taiki-e/portable-atomic - **`float`**
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`**
Use `std`. diff --git a/src/imp/float/int.rs b/src/imp/float/int.rs index 61f5b584..bda88364 100644 --- a/src/imp/float/int.rs +++ b/src/imp/float/int.rs @@ -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); +} diff --git a/src/imp/float/mod.rs b/src/imp/float/mod.rs index afc89032..a36f0983 100644 --- a/src/imp/float/mod.rs +++ b/src/imp/float/mod.rs @@ -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; +} diff --git a/src/lib.rs b/src/lib.rs index 6501e208..26e28e1b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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). @@ -64,7 +65,12 @@ See the [`atomic128` module's readme](https://github.com/taiki-e/portable-atomic - **`float`**
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`**
Use `std`. @@ -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. @@ -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, @@ -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))] @@ -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); @@ -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 diff --git a/src/tests/helper.rs b/src/tests/helper.rs index 364a5b8c..e98f8ec2 100644 --- a/src/tests/helper.rs +++ b/src/tests/helper.rs @@ -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 { @@ -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 { @@ -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; } @@ -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); @@ -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); @@ -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(..)) + } +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 38c63438..553f7ab5 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -35,10 +35,14 @@ test_atomic_int_pub!(u64); test_atomic_int_pub!(i128); test_atomic_int_pub!(u128); +#[cfg(all(feature = "float", portable_atomic_unstable_f16))] +test_atomic_float_pub!(f16); #[cfg(feature = "float")] test_atomic_float_pub!(f32); #[cfg(feature = "float")] test_atomic_float_pub!(f64); +#[cfg(all(feature = "float", portable_atomic_unstable_f128))] +test_atomic_float_pub!(f128); #[deny(improper_ctypes)] extern "C" { @@ -54,15 +58,17 @@ extern "C" { fn _atomic_u32_ffi_safety(_: AtomicU32); fn _atomic_i64_ffi_safety(_: AtomicI64); fn _atomic_u64_ffi_safety(_: AtomicU64); - // TODO: 128-bit integers are not FFI safe - // https://github.com/rust-lang/unsafe-code-guidelines/issues/119 - // https://github.com/rust-lang/rust/issues/54341 + // TODO: https://github.com/rust-lang/lang-team/issues/255 // fn _atomic_i128_ffi_safety(_: AtomicI128); // fn _atomic_u128_ffi_safety(_: AtomicU128); + #[cfg(all(feature = "float", portable_atomic_unstable_f16))] + fn _atomic_f16_ffi_safety(_: AtomicF16); #[cfg(feature = "float")] fn _atomic_f32_ffi_safety(_: AtomicF32); #[cfg(feature = "float")] fn _atomic_f64_ffi_safety(_: AtomicF64); + #[cfg(all(feature = "float", portable_atomic_unstable_f128))] + fn _atomic_f128_ffi_safety(_: AtomicF128); } #[test] @@ -75,10 +81,18 @@ fn test_is_lock_free() { assert!(AtomicI16::is_lock_free()); assert!(AtomicU16::is_always_lock_free()); assert!(AtomicU16::is_lock_free()); + #[cfg(all(feature = "float", portable_atomic_unstable_f16))] + assert!(AtomicF16::is_always_lock_free()); + #[cfg(all(feature = "float", portable_atomic_unstable_f16))] + assert!(AtomicF16::is_lock_free()); assert!(AtomicI32::is_always_lock_free()); assert!(AtomicI32::is_lock_free()); assert!(AtomicU32::is_always_lock_free()); assert!(AtomicU32::is_lock_free()); + #[cfg(feature = "float")] + assert!(AtomicF32::is_always_lock_free()); + #[cfg(feature = "float")] + assert!(AtomicF32::is_lock_free()); #[cfg(not(portable_atomic_no_cfg_target_has_atomic))] { if cfg!(any( @@ -97,6 +111,10 @@ fn test_is_lock_free() { assert!(AtomicI64::is_lock_free()); assert!(AtomicU64::is_always_lock_free()); assert!(AtomicU64::is_lock_free()); + #[cfg(feature = "float")] + assert!(AtomicF64::is_always_lock_free()); + #[cfg(feature = "float")] + assert!(AtomicF64::is_lock_free()); } else if cfg!(all( feature = "fallback", target_arch = "arm", @@ -110,15 +128,23 @@ fn test_is_lock_free() { )) { assert!(!AtomicI64::is_always_lock_free()); assert!(!AtomicU64::is_always_lock_free()); + #[cfg(feature = "float")] + assert!(!AtomicF64::is_always_lock_free()); assert!(AtomicI64::is_lock_free()); assert!(AtomicU64::is_lock_free()); + #[cfg(feature = "float")] + assert!(AtomicF64::is_lock_free()); } else { assert!(!AtomicI64::is_always_lock_free()); assert!(!AtomicU64::is_always_lock_free()); + #[cfg(feature = "float")] + assert!(!AtomicF64::is_always_lock_free()); #[cfg(not(target_arch = "riscv32"))] { assert!(!AtomicI64::is_lock_free()); assert!(!AtomicU64::is_lock_free()); + #[cfg(feature = "float")] + assert!(!AtomicF64::is_lock_free()); } #[cfg(target_arch = "riscv32")] { @@ -131,6 +157,10 @@ fn test_is_lock_free() { assert!(!AtomicI128::is_lock_free()); assert!(!AtomicU128::is_always_lock_free()); assert!(!AtomicU128::is_lock_free()); + #[cfg(all(feature = "float", portable_atomic_unstable_f128))] + assert!(!AtomicF128::is_always_lock_free()); + #[cfg(all(feature = "float", portable_atomic_unstable_f128))] + assert!(!AtomicF128::is_lock_free()); } else if cfg!(any( target_arch = "aarch64", all(target_arch = "arm64ec", not(portable_atomic_no_asm)), @@ -159,9 +189,15 @@ fn test_is_lock_free() { assert!(AtomicI128::is_lock_free()); assert!(AtomicU128::is_always_lock_free()); assert!(AtomicU128::is_lock_free()); + #[cfg(all(feature = "float", portable_atomic_unstable_f128))] + assert!(AtomicF128::is_always_lock_free()); + #[cfg(all(feature = "float", portable_atomic_unstable_f128))] + assert!(AtomicF128::is_lock_free()); } else { assert!(!AtomicI128::is_always_lock_free()); assert!(!AtomicU128::is_always_lock_free()); + #[cfg(all(feature = "float", portable_atomic_unstable_f128))] + assert!(!AtomicF128::is_always_lock_free()); #[cfg(not(any( target_arch = "x86_64", target_arch = "powerpc64", @@ -170,6 +206,8 @@ fn test_is_lock_free() { { assert!(!AtomicI128::is_lock_free()); assert!(!AtomicU128::is_lock_free()); + #[cfg(all(feature = "float", portable_atomic_unstable_f128))] + assert!(!AtomicF128::is_lock_free()); } #[cfg(target_arch = "x86_64")] { @@ -181,6 +219,8 @@ fn test_is_lock_free() { )) && std::is_x86_feature_detected!("cmpxchg16b"); assert_eq!(AtomicI128::is_lock_free(), has_cmpxchg16b); assert_eq!(AtomicU128::is_lock_free(), has_cmpxchg16b); + #[cfg(all(feature = "float", portable_atomic_unstable_f128))] + assert_eq!(AtomicF128::is_lock_free(), has_cmpxchg16b); } #[cfg(target_arch = "powerpc64")] { @@ -425,6 +465,7 @@ fn test_serde() { t!(AtomicU64, u64, U64); t!(AtomicI128, i128, I128); t!(AtomicU128, u128, U128); + // TODO(f16_and_f128): Test f16 & f128 once stabilized. #[cfg(feature = "float")] t!(AtomicF32, f32, F32); #[cfg(feature = "float")] diff --git a/src/utils.rs b/src/utils.rs index c4ab2d91..d22a8c1d 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -134,14 +134,15 @@ macro_rules! const_fn { /// Implements `core::fmt::Debug` and `serde::{Serialize, Deserialize}` (when serde /// feature is enabled) for atomic bool, integer, or float. macro_rules! impl_debug_and_serde { + // TODO(f16_and_f128): Implement serde traits for f16 & f128 once stabilized. + (AtomicF16) => { + impl_debug!(AtomicF16); + }; + (AtomicF128) => { + impl_debug!(AtomicF128); + }; ($atomic_type:ident) => { - impl fmt::Debug for $atomic_type { - #[inline] // fmt is not hot path, but #[inline] on fmt seems to still be useful: https://github.com/rust-lang/rust/pull/117727 - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // std atomic types use Relaxed in Debug::fmt: https://github.com/rust-lang/rust/blob/1.80.0/library/core/src/sync/atomic.rs#L2166 - fmt::Debug::fmt(&self.load(Ordering::Relaxed), f) - } - } + impl_debug!($atomic_type); #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl serde::ser::Serialize for $atomic_type { @@ -167,6 +168,17 @@ macro_rules! impl_debug_and_serde { } }; } +macro_rules! impl_debug { + ($atomic_type:ident) => { + impl fmt::Debug for $atomic_type { + #[inline] // fmt is not hot path, but #[inline] on fmt seems to still be useful: https://github.com/rust-lang/rust/pull/117727 + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // std atomic types use Relaxed in Debug::fmt: https://github.com/rust-lang/rust/blob/1.80.0/library/core/src/sync/atomic.rs#L2166 + fmt::Debug::fmt(&self.load(Ordering::Relaxed), f) + } + } + }; +} // We do not provide `nand` because it cannot be optimized on neither x86 nor MSP430. // https://godbolt.org/z/ahWejchbT diff --git a/tests/api-test/src/helper.rs b/tests/api-test/src/helper.rs index 63d6d482..092a2fe0 100644 --- a/tests/api-test/src/helper.rs +++ b/tests/api-test/src/helper.rs @@ -394,6 +394,18 @@ macro_rules! __test_atomic_float { } __run_test!(fetch_max); fn fetch_max() { + if core::mem::size_of::<$float_type>() == 16 + && cfg!(any( + target_arch = "arm", + target_arch = "mips", + target_arch = "mips32r6", + target_vendor = "apple", + windows, + )) + { + // TODO(f128): + return; + } for &order in &helper::SWAP_ORDERINGS { let a = <$atomic_type>::new(23.); assert_eq!(a.fetch_max(22., order), 23.); @@ -409,6 +421,18 @@ macro_rules! __test_atomic_float { } __run_test!(fetch_min); fn fetch_min() { + if core::mem::size_of::<$float_type>() == 16 + && cfg!(any( + target_arch = "arm", + target_arch = "mips", + target_arch = "mips32r6", + target_vendor = "apple", + windows, + )) + { + // TODO(f128): + return; + } for &order in &helper::SWAP_ORDERINGS { let a = <$atomic_type>::new(23.); assert_eq!(a.fetch_min(24., order), 23.); diff --git a/tests/api-test/src/lib.rs b/tests/api-test/src/lib.rs index 107b4aa6..0070854e 100644 --- a/tests/api-test/src/lib.rs +++ b/tests/api-test/src/lib.rs @@ -1,12 +1,18 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT #![no_std] +#![cfg_attr(portable_atomic_unstable_f16, feature(f16))] +#![cfg_attr(portable_atomic_unstable_f128, feature(f128))] #![allow(unused_imports)] #[macro_use] mod helper; use portable_atomic as atomic; +#[cfg(all(feature = "float", portable_atomic_unstable_f128))] +use portable_atomic::AtomicF128; +#[cfg(all(feature = "float", portable_atomic_unstable_f16))] +use portable_atomic::AtomicF16; use portable_atomic::{ hint, AtomicBool, AtomicI128, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicPtr, AtomicU128, AtomicU16, AtomicU32, AtomicU64, AtomicU8, AtomicUsize, Ordering, @@ -74,10 +80,14 @@ pub fn all() { test_atomic_int!(u64); test_atomic_int!(i128); test_atomic_int!(u128); + #[cfg(all(feature = "float", portable_atomic_unstable_f16))] + test_atomic_float!(f16); #[cfg(feature = "float")] test_atomic_float!(f32); #[cfg(feature = "float")] test_atomic_float!(f64); + #[cfg(all(feature = "float", portable_atomic_unstable_f128))] + test_atomic_float!(f128); } #[cfg(test)] diff --git a/tools/build.sh b/tools/build.sh index ff916c54..669d1103 100755 --- a/tools/build.sh +++ b/tools/build.sh @@ -349,6 +349,10 @@ build() { mips-*-linux-* | mipsel-*-linux-*) target_rustflags+=" -C opt-level=1" ;; esac fi + if [[ "${base_rustflags}" == *"unqualified_local_imports"* ]]; then + [[ "${target_rustflags}" == *"portable_atomic_unstable_f16"* ]] || target_rustflags+=" --cfg portable_atomic_unstable_f16 --cfg quickcheck_unstable_f16 --cfg rand_unstable_f16" + [[ "${target_rustflags}" == *"portable_atomic_unstable_f128"* ]] || target_rustflags+=" --cfg portable_atomic_unstable_f128 --cfg quickcheck_unstable_f128 --cfg rand_unstable_f128" + fi if [[ -n "${TESTS:-}" ]]; then # We use std in main tests, so we cannot build them on no-std targets.