From 6d95c56a40724a5c4c62a8f3d2afa1f7725da067 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Tue, 24 Jan 2023 23:28:44 +0900 Subject: [PATCH] aarch64: Support detecting FEAT_LSE on Windows --- src/imp/atomic128/aarch64.rs | 3 +- src/imp/atomic128/detect/aarch64_windows.rs | 113 ++++++++++++++++++++ 2 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 src/imp/atomic128/detect/aarch64_windows.rs diff --git a/src/imp/atomic128/aarch64.rs b/src/imp/atomic128/aarch64.rs index f3da91ab6..3e27dd49a 100644 --- a/src/imp/atomic128/aarch64.rs +++ b/src/imp/atomic128/aarch64.rs @@ -45,7 +45,8 @@ include!("macros.rs"); -#[path = "detect/aarch64_std.rs"] +#[cfg_attr(target_os = "windows", path = "detect/aarch64_windows.rs")] +#[cfg_attr(not(target_os = "windows"), path = "detect/aarch64_std.rs")] mod detect; #[cfg(not(portable_atomic_no_asm))] diff --git a/src/imp/atomic128/detect/aarch64_windows.rs b/src/imp/atomic128/detect/aarch64_windows.rs new file mode 100644 index 000000000..1d212d966 --- /dev/null +++ b/src/imp/atomic128/detect/aarch64_windows.rs @@ -0,0 +1,113 @@ +// As of nightly-2023-01-23, is_aarch64_feature_detected doesn't support detecting FEAT_LSE on Windows. +// https://github.com/rust-lang/stdarch/blob/a0c30f3e3c75adcd6ee7efc94014ebcead61c507/crates/std_detect/src/detect/os/windows/aarch64.rs +// https://github.com/rust-lang/stdarch/pull/1373 +// +// Refs: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent + +#![cfg_attr( + any( + portable_atomic_no_aarch64_target_feature, + portable_atomic_no_outline_atomics, + any(target_feature = "lse", portable_atomic_target_feature = "lse") + ), + allow(dead_code) +)] + +include!("common.rs"); + +use core::sync::atomic::{AtomicU32, Ordering}; + +impl CpuInfo { + const INIT: u32 = 0; + const HAS_LSE: u32 = 1; +} + +#[inline] +pub(crate) fn has_lse() -> bool { + #[cfg(any(target_feature = "lse", portable_atomic_target_feature = "lse"))] + { + // FEAT_LSE is statically available. + true + } + #[cfg(not(any(target_feature = "lse", portable_atomic_target_feature = "lse")))] + { + detect().test(CpuInfo::HAS_LSE) + } +} + +#[allow(clippy::upper_case_acronyms)] +#[inline] +fn _detect(info: &mut CpuInfo) { + type DWORD = u32; + type BOOL = i32; + + const FALSE: BOOL = 0; + // Defined in winnt.h of Windows SDK. + const PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE: DWORD = 34; + + extern "system" { + fn IsProcessorFeaturePresent(ProcessorFeature: DWORD) -> BOOL; + } + + info.set(CpuInfo::INIT); + // SAFETY: calling IsProcessorFeaturePresent is safe, and FALSE is also + // returned if the HAL does not support detection of the specified feature. + if unsafe { IsProcessorFeaturePresent(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE) != FALSE } { + info.set(CpuInfo::HAS_LSE); + } +} + +#[inline] +fn detect() -> CpuInfo { + static CACHE: AtomicU32 = AtomicU32::new(0); + let mut info = CpuInfo(CACHE.load(Ordering::Relaxed)); + if info.0 != 0 { + return info; + } + _detect(&mut info); + CACHE.store(info.0, Ordering::Relaxed); + info +} + +#[allow(clippy::undocumented_unsafe_blocks)] +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_bit_flags() { + let mut x = CpuInfo(0); + assert!(!x.test(CpuInfo::INIT)); + assert!(!x.test(CpuInfo::HAS_LSE)); + x.set(CpuInfo::INIT); + assert!(x.test(CpuInfo::INIT)); + assert!(!x.test(CpuInfo::HAS_LSE)); + x.set(CpuInfo::HAS_LSE); + assert!(x.test(CpuInfo::INIT)); + assert!(x.test(CpuInfo::HAS_LSE)); + } + + #[test] + fn test_detect() { + if has_lse() { + assert!(detect().test(CpuInfo::HAS_LSE)); + #[cfg(any( + target_feature = "lse", + portable_atomic_target_feature = "lse", + not(portable_atomic_no_aarch64_target_feature), + ))] + unsafe { + use core::cell::UnsafeCell; + let v = UnsafeCell::new(0); + assert_eq!( + super::super::_compare_exchange_casp(v.get(), 0, 1, Ordering::SeqCst), + 0 + ); + assert_eq!(*v.get(), 1); + } + } else { + assert!(!detect().test(CpuInfo::HAS_LSE)); + assert!(!std::arch::is_aarch64_feature_detected!("lse")); + } + } +}