diff --git a/library/stdarch/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/stdarch/ci/docker/aarch64-unknown-linux-gnu/Dockerfile index 4e3bff0ac0a1..68261a2f033d 100644 --- a/library/stdarch/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ b/library/stdarch/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -8,6 +8,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ qemu-user \ make \ file + ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER="qemu-aarch64 -L /usr/aarch64-linux-gnu" \ OBJDUMP=aarch64-linux-gnu-objdump diff --git a/library/stdarch/ci/run-docker.sh b/library/stdarch/ci/run-docker.sh index fe9abac13eef..d08a164be366 100755 --- a/library/stdarch/ci/run-docker.sh +++ b/library/stdarch/ci/run-docker.sh @@ -4,10 +4,11 @@ set -ex run() { - echo $1 + echo "Building docker container for TARGET=${1}" docker build -t stdsimd ci/docker/$1 mkdir -p target target=$(echo $1 | sed 's/-emulated//') + echo "Running docker" docker run \ --user `id -u`:`id -g` \ --rm \ diff --git a/library/stdarch/ci/run.sh b/library/stdarch/ci/run.sh index 1d4be7e09f14..8c8f18c37dca 100755 --- a/library/stdarch/ci/run.sh +++ b/library/stdarch/ci/run.sh @@ -20,9 +20,10 @@ FEATURES_STD="${FEATURES},std" echo "RUSTFLAGS=${RUSTFLAGS}" echo "FEATURES=${FEATURES}" +echo "OBJDUMP=${OBJDUMP}" -cargo test --target $TARGET --features $FEATURES -cargo test --release --target $TARGET --features $FEATURES +cargo test --target $TARGET --features $FEATURES --verbose -- --nocapture +cargo test --release --target $TARGET --features $FEATURES --verbose -- --nocapture -cargo test --target $TARGET --features $FEATURES_STD -cargo test --release --target $TARGET --features $FEATURES_STD +cargo test --target $TARGET --features $FEATURES_STD --verbose -- --nocapture +cargo test --release --target $TARGET --features $FEATURES_STD --verbose -- --nocapture diff --git a/library/stdarch/src/lib.rs b/library/stdarch/src/lib.rs index 05df07fa21a6..add34c2742ef 100644 --- a/library/stdarch/src/lib.rs +++ b/library/stdarch/src/lib.rs @@ -159,8 +159,29 @@ pub mod vendor { pub use aarch64::*; pub use nvptx::*; + + #[cfg(any( + // x86/x86_64: + any(target_arch = "x86", target_arch = "x86_64"), + // linux + std + (arm|aarch64): + all(target_os = "linux", + feature = "std", + any(target_arch = "arm", target_arch = "aarch64")) + ))] + pub use runtime::{__unstable_detect_feature, __Feature}; } +#[cfg(any( + // x86/x86_64: + any(target_arch = "x86", target_arch = "x86_64"), + // linux + std + (arm|aarch64): + all(target_os = "linux", + feature = "std", + any(target_arch = "arm", target_arch = "aarch64")) +))] +#[macro_use] +mod runtime; + #[macro_use] mod macros; mod simd_llvm; @@ -204,7 +225,6 @@ mod v16 { } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -#[macro_use] mod x86; #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] diff --git a/library/stdarch/src/macros.rs b/library/stdarch/src/macros.rs index c2009fa9391d..563e196b648f 100644 --- a/library/stdarch/src/macros.rs +++ b/library/stdarch/src/macros.rs @@ -373,56 +373,6 @@ pub fn $cast(self) -> ::simd::$toty { } } -/// Is a feature supported by the host CPU? -/// -/// This macro performs run-time feature detection. It returns true if the host -/// CPU in which the binary is running on supports a particular feature. -#[macro_export] -macro_rules! cfg_feature_enabled { - ($name:tt) => ( - { - #[cfg(target_feature = $name)] - { - true - } - #[cfg(not(target_feature = $name))] - { - __unstable_detect_feature!($name) - } - } - ) -} - -/// On ARM features are only detected at compile-time using -/// cfg(target_feature), so if this macro is executed the -/// feature is not supported. -#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] -#[macro_export] -#[doc(hidden)] -macro_rules! __unstable_detect_feature { - ("neon") => { false }; - ($t:tt) => { compile_error!(concat!("unknown target feature: ", $t)) }; -} - -/// In all unsupported architectures using the macro is an error -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64", - target_arch = "arm", target_arch = "aarch64")))] -#[macro_export] -#[doc(hidden)] -macro_rules! __unstable_detect_feature { - ($t:tt) => { compile_error!(concat!("unknown target feature: ", $t)) }; -} - -#[cfg(test)] -mod tests { - #[cfg(target_arch = "x86_64")] - #[test] - fn test_macros() { - assert!(cfg_feature_enabled!("sse")); - } -} - - #[cfg(test)] #[macro_export] macro_rules! test_arithmetic_ { diff --git a/library/stdarch/src/runtime/aarch64.rs b/library/stdarch/src/runtime/aarch64.rs new file mode 100644 index 000000000000..5d10fc06e3ab --- /dev/null +++ b/library/stdarch/src/runtime/aarch64.rs @@ -0,0 +1,56 @@ +//! Run-time feature detection on ARM Aarch64. +use super::{bit, linux}; + +#[macro_export] +#[doc(hidden)] +macro_rules! __unstable_detect_feature { + ("neon") => { + // FIXME: this should be removed once we rename Aarch64 neon to asimd + $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::asimd{}) + }; + ("asimd") => { + $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::asimd{}) + }; + ("pmull") => { + $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::pmull{}) + }; + ($t:tt) => { compile_error!(concat!("unknown arm target feature: ", $t)) }; +} + +/// ARM Aarch64 CPU Feature enum. Each variant denotes a position in a bitset +/// for a particular feature. +/// +/// PLEASE: do not use this, it is an implementation detail subject to change. +#[doc(hidden)] +#[allow(non_camel_case_types)] +#[repr(u8)] +pub enum __Feature { + /// ARM Advanced SIMD (ASIMD) - Aarch64 + asimd, + /// Polynomial Multiply + pmull, +} + +pub fn detect_features(mut x: T) -> usize { + let value: usize = 0; + { + let mut enable_feature = |f| { + if x.has_feature(&f) { + bit::set(value, f as u32); + } + }; + enable_feature(__Feature::asimd); + enable_feature(__Feature::pmull); + } + value +} + +impl linux::FeatureQuery for linux::CpuInfo { + fn has_feature(&mut self, x: &__Feature) -> bool { + use self::__Feature::*; + match *x { + asimd => self.field("Features").has("asimd"), + pmull => self.field("Features").has("pmull"), + } + } +} diff --git a/library/stdarch/src/runtime/arm.rs b/library/stdarch/src/runtime/arm.rs new file mode 100644 index 000000000000..60ef909fca12 --- /dev/null +++ b/library/stdarch/src/runtime/arm.rs @@ -0,0 +1,66 @@ +//! Run-time feature detection on ARM Aarch32. + +use super::{bit, linux}; + +#[macro_export] +#[doc(hidden)] +macro_rules! __unstable_detect_feature { + ("neon") => { + $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::neon{}) + }; + ("pmull") => { + $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::pmull{}) + }; + ($t:tt) => { compile_error!(concat!("unknown arm target feature: ", $t)) }; +} + +/// ARM CPU Feature enum. Each variant denotes a position in a bitset for a +/// particular feature. +/// +/// PLEASE: do not use this, it is an implementation detail subject to change. +#[doc(hidden)] +#[allow(non_camel_case_types)] +#[repr(u8)] +pub enum __Feature { + /// ARM Advanced SIMD (NEON) - Aarch32 + neon, + /// Polynomial Multiply + pmull, +} + +pub fn detect_features(mut x: T) -> usize { + let value: usize = 0; + { + let mut enable_feature = |f| { + if x.has_feature(&f) { + bit::set(value, f as u32); + } + }; + enable_feature(__Feature::neon); + enable_feature(__Feature::pmull); + } + value +} + +/// Is the CPU known to have a broken NEON unit? +/// +/// See https://crbug.com/341598. +fn has_broken_neon(cpuinfo: &linux::CpuInfo) -> bool { + cpuinfo.field("CPU implementer") == "0x51" + && cpuinfo.field("CPU architecture") == "7" + && cpuinfo.field("CPU variant") == "0x1" + && cpuinfo.field("CPU part") == "0x04d" + && cpuinfo.field("CPU revision") == "0" +} + +impl linux::FeatureQuery for linux::CpuInfo { + fn has_feature(&mut self, x: &__Feature) -> bool { + use self::__Feature::*; + match *x { + neon => { + self.field("Features").has("neon") && !has_broken_neon(self) + } + pmull => self.field("Features").has("pmull"), + } + } +} diff --git a/library/stdarch/src/runtime/bit.rs b/library/stdarch/src/runtime/bit.rs new file mode 100644 index 000000000000..42483e5225e9 --- /dev/null +++ b/library/stdarch/src/runtime/bit.rs @@ -0,0 +1,11 @@ +//! Bit manipulation utilities + +/// Sets the `bit` of `x`. +pub const fn set(x: usize, bit: u32) -> usize { + x | 1 << bit +} + +/// Tests the `bit` of `x`. +pub const fn test(x: usize, bit: u32) -> bool { + x & (1 << bit) != 0 +} diff --git a/library/stdarch/src/runtime/cache.rs b/library/stdarch/src/runtime/cache.rs new file mode 100644 index 000000000000..6ec39e98e890 --- /dev/null +++ b/library/stdarch/src/runtime/cache.rs @@ -0,0 +1,29 @@ +//! Cache of run-time feature detection + +use super::bit; +use std::sync::atomic::{AtomicUsize, Ordering}; + +/// This global variable is a bitset used to cache the features supported by +/// the +/// CPU. +static CACHE: AtomicUsize = AtomicUsize::new(::std::usize::MAX); + +/// Test the `bit` of the storage. If the storage has not been initialized, +/// initializes it with the result of `f()`. +/// +/// On its first invocation, it detects the CPU features and caches them in the +/// `FEATURES` global variable as an `AtomicUsize`. +/// +/// It uses the `__Feature` variant to index into this variable as a bitset. If +/// the bit is set, the feature is enabled, and otherwise it is disabled. +/// +/// PLEASE: do not use this, it is an implementation detail subject to change. +pub fn test(bit: u32, f: F) -> bool +where + F: FnOnce() -> usize, +{ + if CACHE.load(Ordering::Relaxed) == ::std::usize::MAX { + CACHE.store(f(), Ordering::Relaxed); + } + bit::test(CACHE.load(Ordering::Relaxed), bit) +} diff --git a/library/stdarch/src/runtime/linux/cpuinfo.rs b/library/stdarch/src/runtime/linux/cpuinfo.rs new file mode 100644 index 000000000000..0b18c41cef5a --- /dev/null +++ b/library/stdarch/src/runtime/linux/cpuinfo.rs @@ -0,0 +1,211 @@ +//! Reads /proc/cpuinfo on Linux systems + +/// cpuinfo +pub struct CpuInfo { + raw: String, +} + +/// Field of cpuinfo +#[derive(Debug)] +pub struct CpuInfoField<'a>(Option<&'a str>); + +impl<'a> PartialEq<&'a str> for CpuInfoField<'a> { + fn eq(&self, other: &&'a str) -> bool { + match self.0 { + None => other.len() == 0, + Some(f) => f == other.trim(), + } + } +} + +impl<'a> CpuInfoField<'a> { + pub fn new<'b>(v: Option<&'b str>) -> CpuInfoField<'b> { + match v { + None => CpuInfoField::<'b>(None), + Some(f) => CpuInfoField::<'b>(Some(f.trim())), + } + } + /// Does the field exist? + pub fn exists(&self) -> bool { + self.0.is_some() + } + /// Does the field contain `other`? + pub fn has(&self, other: &str) -> bool { + match self.0 { + None => other.len() == 0, + Some(f) => { + let other = other.trim(); + for v in f.split(" ") { + if v == other { + return true; + } + } + false + } + } + } +} + +impl CpuInfo { + /// Reads /proc/cpuinfo into CpuInfo. + pub fn new() -> Result { + use std::io::Read; + let mut file = ::std::fs::File::open("/proc/cpuinfo")?; + let mut cpui = CpuInfo { raw: String::new() }; + file.read_to_string(&mut cpui.raw)?; + Ok(cpui) + } + /// Returns the value of the cpuinfo `field`. + pub fn field(&self, field: &str) -> CpuInfoField { + for l in self.raw.lines() { + if l.trim().starts_with(field) { + return CpuInfoField(l.split(": ").skip(1).next()); + } + } + CpuInfoField(None) + } + + /// Returns the `raw` contents of `/proc/cpuinfo` + fn raw(&self) -> &String { + &self.raw + } + + fn from_str(other: &str) -> Result { + Ok(CpuInfo { + raw: String::from(other), + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[cfg(target_os = "linux")] + #[test] + fn test_cpuinfo_linux() { + let cpuinfo = CpuInfo::new().unwrap(); + if cpuinfo.field("vendor_id") == "GenuineIntel" { + assert!(cpuinfo.field("flags").exists()); + assert!(!cpuinfo.field("vendor33_id").exists()); + assert!(cpuinfo.field("flags").has("sse")); + assert!(!cpuinfo.field("flags").has("avx314")); + } + println!("{}", cpuinfo.raw()); + } + + + const CORE_DUO_T6500: &str = r"processor : 0 +vendor_id : GenuineIntel +cpu family : 6 +model : 23 +model name : Intel(R) Core(TM)2 Duo CPU T6500 @ 2.10GHz +stepping : 10 +microcode : 0xa0b +cpu MHz : 1600.000 +cache size : 2048 KB +physical id : 0 +siblings : 2 +core id : 0 +cpu cores : 2 +apicid : 0 +initial apicid : 0 +fdiv_bug : no +hlt_bug : no +f00f_bug : no +coma_bug : no +fpu : yes +fpu_exception : yes +cpuid level : 13 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs bts aperfmperf pni dtes64 monitor ds_cpl est tm2 ssse3 cx16 xtpr pdcm sse4_1 xsave lahf_lm dtherm +bogomips : 4190.43 +clflush size : 64 +cache_alignment : 64 +address sizes : 36 bits physical, 48 bits virtual +power management: +"; + + #[test] + fn test_cpuinfo_linux_core_duo_t6500() { + let cpuinfo = CpuInfo::from_str(CORE_DUO_T6500).unwrap(); + assert_eq!(cpuinfo.field("vendor_id"), "GenuineIntel"); + assert_eq!(cpuinfo.field("cpu family"), "6"); + assert_eq!(cpuinfo.field("model"), "23"); + assert_eq!( + cpuinfo.field("model name"), + "Intel(R) Core(TM)2 Duo CPU T6500 @ 2.10GHz" + ); + assert_eq!( + cpuinfo.field("flags"), + "fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs bts aperfmperf pni dtes64 monitor ds_cpl est tm2 ssse3 cx16 xtpr pdcm sse4_1 xsave lahf_lm dtherm" + ); + assert!(cpuinfo.field("flags").has("fpu")); + assert!(cpuinfo.field("flags").has("dtherm")); + assert!(cpuinfo.field("flags").has("sse2")); + assert!(!cpuinfo.field("flags").has("avx")); + } + + const ARM_CORTEX_A53: &str = r"Processor : AArch64 Processor rev 3 (aarch64) + processor : 0 + processor : 1 + processor : 2 + processor : 3 + processor : 4 + processor : 5 + processor : 6 + processor : 7 + Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 + CPU implementer : 0x41 + CPU architecture: AArch64 + CPU variant : 0x0 + CPU part : 0xd03 + CPU revision : 3 + + Hardware : HiKey Development Board + "; + + #[test] + fn test_cpuinfo_linux_arm_cortex_a53() { + let cpuinfo = CpuInfo::from_str(ARM_CORTEX_A53).unwrap(); + assert_eq!( + cpuinfo.field("Processor"), + "AArch64 Processor rev 3 (aarch64)" + ); + assert_eq!( + cpuinfo.field("Features"), + "fp asimd evtstrm aes pmull sha1 sha2 crc32" + ); + assert!(cpuinfo.field("Features").has("pmull")); + assert!(!cpuinfo.field("Features").has("neon")); + assert!(cpuinfo.field("Features").has("asimd")); + } + + const ARM_CORTEX_A57: &str = r"Processor : Cortex A57 Processor rev 1 (aarch64) +processor : 0 +processor : 1 +processor : 2 +processor : 3 +Features : fp asimd aes pmull sha1 sha2 crc32 wp half thumb fastmult vfp edsp neon vfpv3 tlsi vfpv4 idiva idivt +CPU implementer : 0x41 +CPU architecture: 8 +CPU variant : 0x1 +CPU part : 0xd07 +CPU revision : 1"; + + #[test] + fn test_cpuinfo_linux_arm_cortex_a57() { + let cpuinfo = CpuInfo::from_str(ARM_CORTEX_A57).unwrap(); + assert_eq!( + cpuinfo.field("Processor"), + "Cortex A57 Processor rev 1 (aarch64)" + ); + assert_eq!( + cpuinfo.field("Features"), + "fp asimd aes pmull sha1 sha2 crc32 wp half thumb fastmult vfp edsp neon vfpv3 tlsi vfpv4 idiva idivt" + ); + assert!(cpuinfo.field("Features").has("pmull")); + assert!(cpuinfo.field("Features").has("neon")); + assert!(cpuinfo.field("Features").has("asimd")); + } +} diff --git a/library/stdarch/src/runtime/linux/mod.rs b/library/stdarch/src/runtime/linux/mod.rs new file mode 100644 index 000000000000..6625152bafbe --- /dev/null +++ b/library/stdarch/src/runtime/linux/mod.rs @@ -0,0 +1,31 @@ +//! Run-time feature detection for ARM on linux +mod cpuinfo; +pub use self::cpuinfo::CpuInfo; + +use super::__Feature; + +pub trait FeatureQuery { + fn has_feature(&mut self, x: &__Feature) -> bool; +} + +fn detect_features_impl(x: T) -> usize { + #[cfg(target_arch = "arm")] + { + super::arm::detect_features(x) + } + #[cfg(target_arch = "aarch64")] + { + super::aarch64::detect_features(x) + } +} + +/// Detects ARM features: +pub fn detect_features() -> usize { + // FIXME: use libc::getauxval, and if that fails /proc/auxv + // Try to read /proc/cpuinfo + if let Ok(v) = cpuinfo::CpuInfo::new() { + return detect_features_impl(v); + } + // Otherwise all features are disabled + 0 +} diff --git a/library/stdarch/src/runtime/macros.rs b/library/stdarch/src/runtime/macros.rs new file mode 100644 index 000000000000..e8278bb295d3 --- /dev/null +++ b/library/stdarch/src/runtime/macros.rs @@ -0,0 +1,39 @@ +//! Run-time feature detection macros. + +/// Is a feature supported by the host CPU? +/// +/// This macro performs run-time feature detection. It returns true if the host +/// CPU in which the binary is running on supports a particular feature. +#[macro_export] +macro_rules! cfg_feature_enabled { + ($name:tt) => ( + { + #[cfg(target_feature = $name)] + { + true + } + #[cfg(not(target_feature = $name))] + { + __unstable_detect_feature!($name) + } + } + ) +} + +/// In all unsupported architectures using the macro is an error +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64", + target_arch = "arm", target_arch = "aarch64")))] +#[macro_export] +#[doc(hidden)] +macro_rules! __unstable_detect_feature { + ($t:tt) => { compile_error!(concat!("unknown target feature: ", $t)) }; +} + +#[cfg(test)] +mod tests { + #[cfg(target_arch = "x86_64")] + #[test] + fn test_macros() { + assert!(cfg_feature_enabled!("sse")); + } +} diff --git a/library/stdarch/src/runtime/mod.rs b/library/stdarch/src/runtime/mod.rs new file mode 100644 index 000000000000..a48b7b20ce58 --- /dev/null +++ b/library/stdarch/src/runtime/mod.rs @@ -0,0 +1,40 @@ +//! Run-time feature detection +mod cache; +mod bit; + +#[macro_use] +mod macros; + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#[macro_use] +mod x86; +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +pub use self::x86::__Feature; +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +use self::x86::detect_features; + +#[cfg(all(target_arch = "arm", target_os = "linux", feature = "std"))] +#[macro_use] +mod arm; +#[cfg(all(target_arch = "arm", target_os = "linux", feature = "std"))] +pub use self::arm::__Feature; + +#[cfg(all(target_arch = "aarch64", target_os = "linux", feature = "std"))] +#[macro_use] +mod aarch64; +#[cfg(all(target_arch = "aarch64", target_os = "linux", feature = "std"))] +pub use self::aarch64::__Feature; + +#[cfg(all(feature = "std", target_os = "linux", + any(target_arch = "arm", target_arch = "aarch64")))] +mod linux; + +#[cfg(all(feature = "std", target_os = "linux", + any(target_arch = "arm", target_arch = "aarch64")))] +pub use self::linux::detect_features; + +/// Performs run-time feature detection. +#[doc(hidden)] +pub fn __unstable_detect_feature(x: __Feature) -> bool { + cache::test(x as u32, detect_features) +} diff --git a/library/stdarch/src/x86/runtime.rs b/library/stdarch/src/runtime/x86.rs similarity index 91% rename from library/stdarch/src/x86/runtime.rs rename to library/stdarch/src/runtime/x86.rs index 9cbe42808c2e..6d16a5398fe7 100644 --- a/library/stdarch/src/x86/runtime.rs +++ b/library/stdarch/src/runtime/x86.rs @@ -15,7 +15,8 @@ //! this functions queries the CPU for the available features and stores them //! in a global `AtomicUsize` variable. The query is performed by just checking //! whether the feature bit in this global variable is set or cleared. -use std::sync::atomic::{AtomicUsize, Ordering}; + +use super::bit; /// This macro maps the string-literal feature names to values of the /// `__Feature` enum at compile-time. The feature names used are the same as @@ -228,18 +229,6 @@ pub enum __Feature { #[doc(hidden)] __NonExhaustive, } -/// Sets the `bit`-th bit of `x`. -fn set_bit(x: usize, bit: u32) -> usize { - debug_assert!(32 > bit); - x | 1 << bit -} - -/// Tests the `bit`-th bit of `x`. -fn test_bit(x: usize, bit: u32) -> bool { - debug_assert!(32 > bit); - x & (1 << bit) != 0 -} - /// Run-time feature detection on x86 works by using the CPUID instruction. /// /// The [CPUID Wikipedia page][wiki_cpuid] contains @@ -255,9 +244,9 @@ fn test_bit(x: usize, bit: u32) -> bool { /// [wiki_cpuid]: https://en.wikipedia.org/wiki/CPUID /// [intel64_ref]: http://www.intel.de/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf /// [amd64_ref]: http://support.amd.com/TechDocs/24594.pdf -fn detect_features() -> usize { - use super::cpuid::{__cpuid, __cpuid_count, has_cpuid, CpuidResult}; - use super::xsave::_xgetbv; +pub fn detect_features() -> usize { + use vendor::{__cpuid, __cpuid_count, has_cpuid, CpuidResult}; + use vendor::_xgetbv; let mut value: usize = 0; // If the x86 CPU does not support the CPUID instruction then it is too @@ -331,8 +320,8 @@ fn detect_features() -> usize { { // borrows value till the end of this scope: - let mut enable = |r, rb, f| if test_bit(r as usize, rb) { - value = set_bit(value, f as u32); + let mut enable = |r, rb, f| if bit::test(r as usize, rb) { + value = bit::set(value, f as u32); }; enable(proc_info_ecx, 0, __Feature::sse3); @@ -348,7 +337,7 @@ fn detect_features() -> usize { enable(extended_features_ebx, 8, __Feature::bmi2); // `XSAVE` and `AVX` support: - if test_bit(proc_info_ecx as usize, 26) { + if bit::test(proc_info_ecx as usize, 26) { // 0. Here the CPU supports `XSAVE`. // 1. Detect `OSXSAVE`, that is, whether the OS is AVX enabled and @@ -359,7 +348,7 @@ fn detect_features() -> usize { // com/en-us/blogs/2011/04/14/is-avx-enabled // - https://hg.mozilla. // org/mozilla-central/file/64bab5cbb9b6/mozglue/build/SSE.cpp#l190 - let cpu_osxsave = test_bit(proc_info_ecx as usize, 27); + let cpu_osxsave = bit::test(proc_info_ecx as usize, 27); // 2. The OS must have signaled the CPU that it supports saving and // restoring the SSE and AVX registers by setting `XCR0.SSE[1]` and @@ -431,27 +420,6 @@ fn detect_features() -> usize { value } -/// This global variable is a bitset used to cache the features supported by -/// the CPU. -static FEATURES: AtomicUsize = AtomicUsize::new(::std::usize::MAX); - -/// Performs run-time feature detection. -/// -/// On its first invocation, it detects the CPU features and caches them -/// in the `FEATURES` global variable as an `AtomicUsize`. -/// -/// It uses the `__Feature` variant to index into this variable as a bitset. If -/// the bit is set, the feature is enabled, and otherwise it is disabled. -/// -/// PLEASE: do not use this, it is an implementation detail subject to change. -#[doc(hidden)] -pub fn __unstable_detect_feature(x: __Feature) -> bool { - if FEATURES.load(Ordering::Relaxed) == ::std::usize::MAX { - FEATURES.store(detect_features(), Ordering::Relaxed); - } - test_bit(FEATURES.load(Ordering::Relaxed), x as u32) -} - #[cfg(test)] mod tests { #[cfg(feature = "std")] diff --git a/library/stdarch/src/x86/mod.rs b/library/stdarch/src/x86/mod.rs index 990db824d40e..8d57ebd2d9e3 100644 --- a/library/stdarch/src/x86/mod.rs +++ b/library/stdarch/src/x86/mod.rs @@ -20,8 +20,6 @@ #[cfg(not(feature = "intel_sde"))] pub use self::tbm::*; -pub use self::runtime::{__unstable_detect_feature, __Feature}; - /// 128-bit wide signed integer vector type #[allow(non_camel_case_types)] pub type __m128i = ::v128::i8x16; @@ -31,8 +29,6 @@ #[macro_use] mod macros; -#[macro_use] -mod runtime; mod ia32; mod cpuid; diff --git a/library/stdarch/tests/cpu-detection.rs b/library/stdarch/tests/cpu-detection.rs index 4207824c0ec2..c4b4c9627f99 100644 --- a/library/stdarch/tests/cpu-detection.rs +++ b/library/stdarch/tests/cpu-detection.rs @@ -27,9 +27,12 @@ fn works() { // assert_eq!(cfg_feature_enabled!("avx512bw"), information.avx512bw()); // assert_eq!(cfg_feature_enabled!("avx512dq"), information.avx512dq()); // assert_eq!(cfg_feature_enabled!("avx512vl"), information.avx512vl()); - // assert_eq!(cfg_feature_enabled!("avx512ifma"), information.avx512ifma()); - // assert_eq!(cfg_feature_enabled!("avx512vbmi"), information.avx512vbmi()); - // assert_eq!(cfg_feature_enabled!("avx512vpopcntdq"), information.avx512vpopcntdq()); + // assert_eq!(cfg_feature_enabled!("avx512ifma"), + // information.avx512_ifma()); + // assert_eq!(cfg_feature_enabled!("avx512vbmi"), + // information.avx512_vbmi()); + // assert_eq!(cfg_feature_enabled!("avx512vpopcntdq"), + // information.avx512_vpopcntdq()); assert_eq!(cfg_feature_enabled!("fma"), information.fma()); assert_eq!(cfg_feature_enabled!("bmi"), information.bmi1()); assert_eq!(cfg_feature_enabled!("bmi2"), information.bmi2()); @@ -40,6 +43,12 @@ fn works() { assert_eq!(cfg_feature_enabled!("lzcnt"), information.lzcnt()); assert_eq!(cfg_feature_enabled!("xsave"), information.xsave()); assert_eq!(cfg_feature_enabled!("xsaveopt"), information.xsaveopt()); - assert_eq!(cfg_feature_enabled!("xsavec"), information.xsavec_and_xrstor()); - assert_eq!(cfg_feature_enabled!("xsavec"), information.xsaves_xrstors_and_ia32_xss()); + assert_eq!( + cfg_feature_enabled!("xsavec"), + information.xsavec_and_xrstor() + ); + assert_eq!( + cfg_feature_enabled!("xsavec"), + information.xsaves_xrstors_and_ia32_xss() + ); }