aboutsummaryrefslogtreecommitdiff
path: root/vendor/portable-atomic/src/imp/atomic128/detect/common.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/portable-atomic/src/imp/atomic128/detect/common.rs')
-rw-r--r--vendor/portable-atomic/src/imp/atomic128/detect/common.rs395
1 files changed, 395 insertions, 0 deletions
diff --git a/vendor/portable-atomic/src/imp/atomic128/detect/common.rs b/vendor/portable-atomic/src/imp/atomic128/detect/common.rs
new file mode 100644
index 0000000..b87caa3
--- /dev/null
+++ b/vendor/portable-atomic/src/imp/atomic128/detect/common.rs
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+#[derive(Clone, Copy)]
+pub(crate) struct CpuInfo(u32);
+
+impl CpuInfo {
+ const INIT: u32 = 0;
+
+ #[inline]
+ fn set(&mut self, bit: u32) {
+ self.0 = set(self.0, bit);
+ }
+ #[inline]
+ fn test(self, bit: u32) -> bool {
+ test(self.0, bit)
+ }
+}
+
+#[inline]
+fn set(x: u32, bit: u32) -> u32 {
+ x | 1 << bit
+}
+#[inline]
+fn test(x: u32, bit: u32) -> bool {
+ x & (1 << bit) != 0
+}
+
+#[inline]
+pub(crate) fn detect() -> CpuInfo {
+ use core::sync::atomic::{AtomicU32, Ordering};
+
+ static CACHE: AtomicU32 = AtomicU32::new(0);
+ let mut info = CpuInfo(CACHE.load(Ordering::Relaxed));
+ if info.0 != 0 {
+ return info;
+ }
+ info.set(CpuInfo::INIT);
+ // Note: detect_false cfg is intended to make it easy for portable-atomic developers to
+ // test cases such as has_cmpxchg16b == false, has_lse == false,
+ // __kuser_helper_version < 5, etc., and is not a public API.
+ if !cfg!(portable_atomic_test_outline_atomics_detect_false) {
+ _detect(&mut info);
+ }
+ CACHE.store(info.0, Ordering::Relaxed);
+ info
+}
+
+#[cfg(target_arch = "aarch64")]
+impl CpuInfo {
+ /// Whether FEAT_LSE is available
+ const HAS_LSE: u32 = 1;
+ /// Whether FEAT_LSE2 is available
+ #[cfg_attr(not(test), allow(dead_code))]
+ const HAS_LSE2: u32 = 2;
+ /// Whether FEAT_LSE128 is available
+ // This is currently only used in tests.
+ #[cfg(test)]
+ const HAS_LSE128: u32 = 3;
+ /// Whether FEAT_LRCPC3 is available
+ // This is currently only used in tests.
+ #[cfg(test)]
+ const HAS_RCPC3: u32 = 4;
+
+ #[cfg(any(test, not(any(target_feature = "lse", portable_atomic_target_feature = "lse"))))]
+ #[inline]
+ pub(crate) fn has_lse(self) -> bool {
+ self.test(CpuInfo::HAS_LSE)
+ }
+ #[cfg_attr(not(test), allow(dead_code))]
+ #[cfg(any(test, not(any(target_feature = "lse2", portable_atomic_target_feature = "lse2"))))]
+ #[inline]
+ pub(crate) fn has_lse2(self) -> bool {
+ self.test(CpuInfo::HAS_LSE2)
+ }
+ #[cfg(test)]
+ #[inline]
+ pub(crate) fn has_lse128(self) -> bool {
+ self.test(CpuInfo::HAS_LSE128)
+ }
+ #[cfg(test)]
+ #[inline]
+ pub(crate) fn has_rcpc3(self) -> bool {
+ self.test(CpuInfo::HAS_RCPC3)
+ }
+}
+
+#[cfg(target_arch = "x86_64")]
+impl CpuInfo {
+ /// Whether CMPXCHG16B is available
+ const HAS_CMPXCHG16B: u32 = 1;
+ /// Whether VMOVDQA is atomic
+ const HAS_VMOVDQA_ATOMIC: u32 = 2;
+
+ #[cfg(any(
+ test,
+ not(any(target_feature = "cmpxchg16b", portable_atomic_target_feature = "cmpxchg16b")),
+ ))]
+ #[inline]
+ pub(crate) fn has_cmpxchg16b(self) -> bool {
+ self.test(CpuInfo::HAS_CMPXCHG16B)
+ }
+ #[inline]
+ pub(crate) fn has_vmovdqa_atomic(self) -> bool {
+ self.test(CpuInfo::HAS_VMOVDQA_ATOMIC)
+ }
+}
+
+#[cfg(target_arch = "powerpc64")]
+impl CpuInfo {
+ /// Whether lqarx and stqcx. instructions are available
+ const HAS_QUADWORD_ATOMICS: u32 = 1;
+
+ #[cfg(any(
+ test,
+ not(any(
+ target_feature = "quadword-atomics",
+ portable_atomic_target_feature = "quadword-atomics",
+ )),
+ ))]
+ #[inline]
+ pub(crate) fn has_quadword_atomics(self) -> bool {
+ self.test(CpuInfo::HAS_QUADWORD_ATOMICS)
+ }
+}
+
+// core::ffi::c_* (except c_void) requires Rust 1.64, libc will soon require Rust 1.47
+#[cfg(any(target_arch = "aarch64", target_arch = "powerpc64"))]
+#[cfg(not(windows))]
+#[allow(dead_code, non_camel_case_types)]
+mod c_types {
+ pub(crate) type c_void = core::ffi::c_void;
+ // c_{,u}int is {i,u}32 on non-16-bit architectures
+ // https://github.com/rust-lang/rust/blob/1.70.0/library/core/src/ffi/mod.rs#L160
+ // (16-bit architectures currently don't use this module)
+ pub(crate) type c_int = i32;
+ pub(crate) type c_uint = u32;
+ // c_{,u}long is {i,u}64 on non-Windows 64-bit targets, otherwise is {i,u}32
+ // https://github.com/rust-lang/rust/blob/1.70.0/library/core/src/ffi/mod.rs#L176
+ // (Windows currently doesn't use this module - this module is cfg(not(windows)))
+ #[cfg(target_pointer_width = "64")]
+ pub(crate) type c_long = i64;
+ #[cfg(not(target_pointer_width = "64"))]
+ pub(crate) type c_long = i32;
+ #[cfg(target_pointer_width = "64")]
+ pub(crate) type c_ulong = u64;
+ #[cfg(not(target_pointer_width = "64"))]
+ pub(crate) type c_ulong = u32;
+ // c_size_t is currently always usize
+ // https://github.com/rust-lang/rust/blob/1.70.0/library/core/src/ffi/mod.rs#L88
+ pub(crate) type c_size_t = usize;
+ // c_char is u8 by default on most non-Apple/non-Windows ARM/PowerPC/RISC-V/s390x/Hexagon targets
+ // (Linux/Android/FreeBSD/NetBSD/OpenBSD/VxWorks/Fuchsia/QNX Neutrino/Horizon/AIX/z/OS)
+ // https://github.com/rust-lang/rust/blob/1.70.0/library/core/src/ffi/mod.rs#L104
+ // https://github.com/llvm/llvm-project/blob/9734b2256d89cb4c61a4dbf4a3c3f3f942fe9b8c/lldb/source/Utility/ArchSpec.cpp#L712
+ // RISC-V https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/HEAD/riscv-cc.adoc#cc-type-representations
+ // Hexagon https://lists.llvm.org/pipermail/llvm-dev/attachments/20190916/21516a52/attachment-0001.pdf
+ // AIX https://www.ibm.com/docs/en/xl-c-aix/13.1.2?topic=descriptions-qchars
+ // z/OS https://www.ibm.com/docs/en/zos/2.5.0?topic=specifiers-character-types
+ // (macOS is currently the only Apple target that uses this module, and Windows currently doesn't use this module)
+ #[cfg(not(target_os = "macos"))]
+ pub(crate) type c_char = u8;
+ // c_char is i8 on all Apple targets
+ #[cfg(target_os = "macos")]
+ pub(crate) type c_char = i8;
+
+ // Static assertions for C type definitions.
+ #[cfg(test)]
+ const _: fn() = || {
+ use test_helper::{libc, sys};
+ let _: c_int = 0 as std::os::raw::c_int;
+ let _: c_uint = 0 as std::os::raw::c_uint;
+ let _: c_long = 0 as std::os::raw::c_long;
+ let _: c_ulong = 0 as std::os::raw::c_ulong;
+ let _: c_size_t = 0 as libc::size_t; // std::os::raw::c_size_t is unstable
+ let _: c_char = 0 as std::os::raw::c_char;
+ let _: c_char = 0 as sys::c_char;
+ };
+}
+
+#[allow(
+ clippy::alloc_instead_of_core,
+ clippy::std_instead_of_alloc,
+ clippy::std_instead_of_core,
+ clippy::undocumented_unsafe_blocks,
+ clippy::wildcard_imports
+)]
+#[cfg(test)]
+mod tests_common {
+ use super::*;
+
+ #[test]
+ fn test_bit_flags() {
+ let mut x = CpuInfo(0);
+ #[cfg(target_arch = "aarch64")]
+ {
+ assert!(!x.test(CpuInfo::INIT));
+ assert!(!x.test(CpuInfo::HAS_LSE));
+ assert!(!x.test(CpuInfo::HAS_LSE2));
+ assert!(!x.test(CpuInfo::HAS_LSE128));
+ assert!(!x.test(CpuInfo::HAS_RCPC3));
+ x.set(CpuInfo::INIT);
+ assert!(x.test(CpuInfo::INIT));
+ assert!(!x.test(CpuInfo::HAS_LSE));
+ assert!(!x.test(CpuInfo::HAS_LSE2));
+ assert!(!x.test(CpuInfo::HAS_LSE128));
+ assert!(!x.test(CpuInfo::HAS_RCPC3));
+ x.set(CpuInfo::HAS_LSE);
+ assert!(x.test(CpuInfo::INIT));
+ assert!(x.test(CpuInfo::HAS_LSE));
+ assert!(!x.test(CpuInfo::HAS_LSE2));
+ assert!(!x.test(CpuInfo::HAS_LSE128));
+ assert!(!x.test(CpuInfo::HAS_RCPC3));
+ x.set(CpuInfo::HAS_LSE2);
+ assert!(x.test(CpuInfo::INIT));
+ assert!(x.test(CpuInfo::HAS_LSE));
+ assert!(x.test(CpuInfo::HAS_LSE2));
+ assert!(!x.test(CpuInfo::HAS_LSE128));
+ assert!(!x.test(CpuInfo::HAS_RCPC3));
+ x.set(CpuInfo::HAS_LSE128);
+ assert!(x.test(CpuInfo::INIT));
+ assert!(x.test(CpuInfo::HAS_LSE));
+ assert!(x.test(CpuInfo::HAS_LSE2));
+ assert!(x.test(CpuInfo::HAS_LSE128));
+ assert!(!x.test(CpuInfo::HAS_RCPC3));
+ x.set(CpuInfo::HAS_RCPC3);
+ assert!(x.test(CpuInfo::INIT));
+ assert!(x.test(CpuInfo::HAS_LSE));
+ assert!(x.test(CpuInfo::HAS_LSE2));
+ assert!(x.test(CpuInfo::HAS_LSE128));
+ assert!(x.test(CpuInfo::HAS_RCPC3));
+ }
+ #[cfg(target_arch = "x86_64")]
+ {
+ assert!(!x.test(CpuInfo::INIT));
+ assert!(!x.test(CpuInfo::HAS_CMPXCHG16B));
+ assert!(!x.test(CpuInfo::HAS_VMOVDQA_ATOMIC));
+ x.set(CpuInfo::INIT);
+ assert!(x.test(CpuInfo::INIT));
+ assert!(!x.test(CpuInfo::HAS_CMPXCHG16B));
+ assert!(!x.test(CpuInfo::HAS_VMOVDQA_ATOMIC));
+ x.set(CpuInfo::HAS_CMPXCHG16B);
+ assert!(x.test(CpuInfo::INIT));
+ assert!(x.test(CpuInfo::HAS_CMPXCHG16B));
+ assert!(!x.test(CpuInfo::HAS_VMOVDQA_ATOMIC));
+ x.set(CpuInfo::HAS_VMOVDQA_ATOMIC);
+ assert!(x.test(CpuInfo::INIT));
+ assert!(x.test(CpuInfo::HAS_CMPXCHG16B));
+ assert!(x.test(CpuInfo::HAS_VMOVDQA_ATOMIC));
+ }
+ #[cfg(target_arch = "powerpc64")]
+ {
+ assert!(!x.test(CpuInfo::INIT));
+ assert!(!x.test(CpuInfo::HAS_QUADWORD_ATOMICS));
+ x.set(CpuInfo::INIT);
+ assert!(x.test(CpuInfo::INIT));
+ assert!(!x.test(CpuInfo::HAS_QUADWORD_ATOMICS));
+ x.set(CpuInfo::HAS_QUADWORD_ATOMICS);
+ assert!(x.test(CpuInfo::INIT));
+ assert!(x.test(CpuInfo::HAS_QUADWORD_ATOMICS));
+ }
+ }
+
+ #[test]
+ fn print_features() {
+ use std::{fmt::Write as _, io::Write, string::String};
+
+ let mut features = String::new();
+ macro_rules! print_feature {
+ ($name:expr, $enabled:expr $(,)?) => {{
+ let _ = writeln!(features, " {}: {}", $name, $enabled);
+ }};
+ }
+ #[cfg(target_arch = "aarch64")]
+ {
+ features.push_str("run-time:\n");
+ print_feature!("lse", detect().test(CpuInfo::HAS_LSE));
+ print_feature!("lse2", detect().test(CpuInfo::HAS_LSE2));
+ print_feature!("lse128", detect().test(CpuInfo::HAS_LSE128));
+ print_feature!("rcpc3", detect().test(CpuInfo::HAS_RCPC3));
+ features.push_str("compile-time:\n");
+ print_feature!(
+ "lse",
+ cfg!(any(target_feature = "lse", portable_atomic_target_feature = "lse")),
+ );
+ print_feature!(
+ "lse2",
+ cfg!(any(target_feature = "lse2", portable_atomic_target_feature = "lse2")),
+ );
+ }
+ #[cfg(target_arch = "x86_64")]
+ {
+ features.push_str("run-time:\n");
+ print_feature!("cmpxchg16b", detect().test(CpuInfo::HAS_CMPXCHG16B));
+ print_feature!("vmovdqa-atomic", detect().test(CpuInfo::HAS_VMOVDQA_ATOMIC));
+ features.push_str("compile-time:\n");
+ print_feature!(
+ "cmpxchg16b",
+ cfg!(any(
+ target_feature = "cmpxchg16b",
+ portable_atomic_target_feature = "cmpxchg16b",
+ )),
+ );
+ }
+ #[cfg(target_arch = "powerpc64")]
+ {
+ features.push_str("run-time:\n");
+ print_feature!("quadword-atomics", detect().test(CpuInfo::HAS_QUADWORD_ATOMICS));
+ features.push_str("compile-time:\n");
+ print_feature!(
+ "quadword-atomics",
+ cfg!(any(
+ target_feature = "quadword-atomics",
+ portable_atomic_target_feature = "quadword-atomics",
+ )),
+ );
+ }
+ let stdout = std::io::stderr();
+ let mut stdout = stdout.lock();
+ let _ = stdout.write_all(features.as_bytes());
+ }
+
+ #[cfg(target_arch = "x86_64")]
+ #[test]
+ #[cfg_attr(portable_atomic_test_outline_atomics_detect_false, ignore)]
+ fn test_detect() {
+ if detect().has_cmpxchg16b() {
+ assert!(detect().test(CpuInfo::HAS_CMPXCHG16B));
+ } else {
+ assert!(!detect().test(CpuInfo::HAS_CMPXCHG16B));
+ }
+ if detect().has_vmovdqa_atomic() {
+ assert!(detect().test(CpuInfo::HAS_VMOVDQA_ATOMIC));
+ } else {
+ assert!(!detect().test(CpuInfo::HAS_VMOVDQA_ATOMIC));
+ }
+ }
+ #[cfg(target_arch = "aarch64")]
+ #[test]
+ #[cfg_attr(portable_atomic_test_outline_atomics_detect_false, ignore)]
+ fn test_detect() {
+ let proc_cpuinfo = test_helper::cpuinfo::ProcCpuinfo::new();
+ if detect().has_lse() {
+ assert!(detect().test(CpuInfo::HAS_LSE));
+ if let Ok(proc_cpuinfo) = proc_cpuinfo {
+ assert!(proc_cpuinfo.lse);
+ }
+ } else {
+ assert!(!detect().test(CpuInfo::HAS_LSE));
+ if let Ok(proc_cpuinfo) = proc_cpuinfo {
+ assert!(!proc_cpuinfo.lse);
+ }
+ }
+ if detect().has_lse2() {
+ assert!(detect().test(CpuInfo::HAS_LSE));
+ assert!(detect().test(CpuInfo::HAS_LSE2));
+ if let Ok(test_helper::cpuinfo::ProcCpuinfo { lse2: Some(lse2), .. }) = proc_cpuinfo {
+ assert!(lse2);
+ }
+ } else {
+ assert!(!detect().test(CpuInfo::HAS_LSE2));
+ if let Ok(test_helper::cpuinfo::ProcCpuinfo { lse2: Some(lse2), .. }) = proc_cpuinfo {
+ assert!(!lse2);
+ }
+ }
+ if detect().has_lse128() {
+ assert!(detect().test(CpuInfo::HAS_LSE));
+ assert!(detect().test(CpuInfo::HAS_LSE2));
+ assert!(detect().test(CpuInfo::HAS_LSE128));
+ } else {
+ assert!(!detect().test(CpuInfo::HAS_LSE128));
+ }
+ if detect().has_rcpc3() {
+ assert!(detect().test(CpuInfo::HAS_RCPC3));
+ } else {
+ assert!(!detect().test(CpuInfo::HAS_RCPC3));
+ }
+ }
+ #[cfg(target_arch = "powerpc64")]
+ #[test]
+ #[cfg_attr(portable_atomic_test_outline_atomics_detect_false, ignore)]
+ fn test_detect() {
+ let proc_cpuinfo = test_helper::cpuinfo::ProcCpuinfo::new();
+ if detect().has_quadword_atomics() {
+ assert!(detect().test(CpuInfo::HAS_QUADWORD_ATOMICS));
+ if let Ok(proc_cpuinfo) = proc_cpuinfo {
+ assert!(proc_cpuinfo.power8);
+ }
+ } else {
+ assert!(!detect().test(CpuInfo::HAS_QUADWORD_ATOMICS));
+ if let Ok(proc_cpuinfo) = proc_cpuinfo {
+ assert!(!proc_cpuinfo.power8);
+ }
+ }
+ }
+}