diff --git a/ci/azure.yml b/ci/azure.yml index bb8f220956..f1269b0426 100644 --- a/ci/azure.yml +++ b/ci/azure.yml @@ -163,7 +163,7 @@ jobs: # TARGET: i686-pc-windows-gnu #i686-pc-windows-msvc: # TARGET: i686-pc-windows-msvc - + - job: StyleAndDocs pool: vmImage: ubuntu-16.04 @@ -186,7 +186,16 @@ jobs: steps: - template: azure-install-rust.yml - script: cargo test --manifest-path crates/stdarch-verify/Cargo.toml - displayName: Automatic verification + displayName: Automatic verification + + - job: EnvOverride + dependsOn: StyleAndDocs + pool: + vmImage: ubuntu-16.04 + steps: + - template: azure-install-rust.yml + - script: RUST_STD_DETECT_UNSTABLE=avx cargo test --manifest-path crates/std_detect/Cargo.toml env_override_no_avx + displayName: std_detect env override # - job: GameBoyAdvance # dependsOn: StyleAndDocs diff --git a/crates/std_detect/Cargo.toml b/crates/std_detect/Cargo.toml index acfcc116f4..857d8a5b9b 100644 --- a/crates/std_detect/Cargo.toml +++ b/crates/std_detect/Cargo.toml @@ -31,6 +31,7 @@ auxv = "0.3.3" cupid = "0.6.0" [features] -default = [ "std_detect_dlsym_getauxval", "std_detect_file_io" ] +default = [ "std_detect_dlsym_getauxval", "std_detect_file_io", "std_detect_env_override" ] std_detect_file_io = [] -std_detect_dlsym_getauxval = [ "libc" ] \ No newline at end of file +std_detect_dlsym_getauxval = [ "libc" ] +std_detect_env_override = [] diff --git a/crates/std_detect/src/detect/cache.rs b/crates/std_detect/src/detect/cache.rs index 92bc4b58d1..9179fbd938 100644 --- a/crates/std_detect/src/detect/cache.rs +++ b/crates/std_detect/src/detect/cache.rs @@ -23,6 +23,12 @@ const fn test_bit(x: u64, bit: u32) -> bool { x & (1 << bit) != 0 } +/// Unset the `bit of `x`. +#[inline] +const fn unset_bit(x: u64, bit: u32) -> u64 { + x & !(1 << bit) +} + /// Maximum number of features that can be cached. const CACHE_CAPACITY: u32 = 63; @@ -37,13 +43,13 @@ impl Default for Initializer { } } +// NOTE: the `debug_assert!` would catch that we do not add more Features than +// the one fitting our cache. impl Initializer { /// Tests the `bit` of the cache. #[allow(dead_code)] #[inline] pub(crate) fn test(self, bit: u32) -> bool { - // FIXME: this way of making sure that the cache is large enough is - // brittle. debug_assert!( bit < CACHE_CAPACITY, "too many features, time to increase the cache size!" @@ -54,8 +60,6 @@ impl Initializer { /// Sets the `bit` of the cache. #[inline] pub(crate) fn set(&mut self, bit: u32) { - // FIXME: this way of making sure that the cache is large enough is - // brittle. debug_assert!( bit < CACHE_CAPACITY, "too many features, time to increase the cache size!" @@ -63,6 +67,17 @@ impl Initializer { let v = self.0; self.0 = set_bit(v, bit); } + + /// Unsets the `bit` of the cache. + #[inline] + pub(crate) fn unset(&mut self, bit: u32) { + debug_assert!( + bit < CACHE_CAPACITY, + "too many features, time to increase the cache size!" + ); + let v = self.0; + self.0 = unset_bit(v, bit); + } } /// This global variable is a cache of the features supported by the CPU. @@ -143,6 +158,24 @@ impl Cache { self.1.store(hi, Ordering::Relaxed); } } +cfg_if! { + if #[cfg(feature = "std_detect_env_override")] { + #[inline(never)] + fn initialize(mut value: Initializer) { + if let Ok(disable) = crate::env::var("RUST_STD_DETECT_UNSTABLE") { + for v in disable.split(" ") { + let _ = super::Feature::from_str(v).map(|v| value.unset(v as u32)); + } + } + CACHE.initialize(value); + } + } else { + #[inline] + fn initialize(value: Initializer) { + CACHE.initialize(value); + } + } +} /// Tests the `bit` of the storage. If the storage has not been initialized, /// initializes it with the result of `f()`. @@ -152,13 +185,17 @@ impl Cache { /// /// 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. +/// +/// If the feature `std_detect_env_override` is enabled looks for the env +/// variable `RUST_STD_DETECT_UNSTABLE` and uses its its content to disable +/// Features that would had been otherwise detected. #[inline] pub(crate) fn test(bit: u32, f: F) -> bool where F: FnOnce() -> Initializer, { if CACHE.is_uninitialized() { - CACHE.initialize(f()); + initialize(f()); } CACHE.test(bit) } diff --git a/crates/std_detect/src/detect/macros.rs b/crates/std_detect/src/detect/macros.rs index 750cf50aa7..c9200d2f1f 100644 --- a/crates/std_detect/src/detect/macros.rs +++ b/crates/std_detect/src/detect/macros.rs @@ -69,6 +69,12 @@ macro_rules! features { Feature::_last => unreachable!(), } } + pub fn from_str(s: &str) -> Result { + match s { + $($feature_lit => Ok(Feature::$feature),)* + _ => Err(()) + } + } } /// Each function performs run-time feature detection for a single diff --git a/crates/std_detect/src/detect/mod.rs b/crates/std_detect/src/detect/mod.rs index 6389a3fd75..cbbc6afab1 100644 --- a/crates/std_detect/src/detect/mod.rs +++ b/crates/std_detect/src/detect/mod.rs @@ -61,6 +61,13 @@ cfg_if! { } #[doc(hidden)] pub mod __is_feature_detected {} + + impl Feature { + #[doc(hidden)] + pub fn from_str(_s: &str) -> Result { Err<()> } + #[doc(hidden)] + pub fn to_str(self) -> &'static str { "" } + } } } } diff --git a/crates/std_detect/src/detect/os/x86.rs b/crates/std_detect/src/detect/os/x86.rs index c653771c43..7888776335 100644 --- a/crates/std_detect/src/detect/os/x86.rs +++ b/crates/std_detect/src/detect/os/x86.rs @@ -243,120 +243,3 @@ pub(crate) fn detect_features() -> cache::Initializer { value } - -#[cfg(test)] -mod tests { - extern crate cupid; - - #[test] - fn dump() { - println!("aes: {:?}", is_x86_feature_detected!("aes")); - println!("pclmulqdq: {:?}", is_x86_feature_detected!("pclmulqdq")); - println!("rdrand: {:?}", is_x86_feature_detected!("rdrand")); - println!("rdseed: {:?}", is_x86_feature_detected!("rdseed")); - println!("tsc: {:?}", is_x86_feature_detected!("tsc")); - println!("sse: {:?}", is_x86_feature_detected!("sse")); - println!("sse2: {:?}", is_x86_feature_detected!("sse2")); - println!("sse3: {:?}", is_x86_feature_detected!("sse3")); - println!("ssse3: {:?}", is_x86_feature_detected!("ssse3")); - println!("sse4.1: {:?}", is_x86_feature_detected!("sse4.1")); - println!("sse4.2: {:?}", is_x86_feature_detected!("sse4.2")); - println!("sse4a: {:?}", is_x86_feature_detected!("sse4a")); - println!("sha: {:?}", is_x86_feature_detected!("sha")); - println!("avx: {:?}", is_x86_feature_detected!("avx")); - println!("avx2: {:?}", is_x86_feature_detected!("avx2")); - println!("avx512f {:?}", is_x86_feature_detected!("avx512f")); - println!("avx512cd {:?}", is_x86_feature_detected!("avx512cd")); - println!("avx512er {:?}", is_x86_feature_detected!("avx512er")); - println!("avx512pf {:?}", is_x86_feature_detected!("avx512pf")); - println!("avx512bw {:?}", is_x86_feature_detected!("avx512bw")); - println!("avx512dq {:?}", is_x86_feature_detected!("avx512dq")); - println!("avx512vl {:?}", is_x86_feature_detected!("avx512vl")); - println!("avx512_ifma {:?}", is_x86_feature_detected!("avx512ifma")); - println!("avx512_vbmi {:?}", is_x86_feature_detected!("avx512vbmi")); - println!( - "avx512_vpopcntdq {:?}", - is_x86_feature_detected!("avx512vpopcntdq") - ); - println!("fma: {:?}", is_x86_feature_detected!("fma")); - println!("abm: {:?}", is_x86_feature_detected!("abm")); - println!("bmi: {:?}", is_x86_feature_detected!("bmi1")); - println!("bmi2: {:?}", is_x86_feature_detected!("bmi2")); - println!("tbm: {:?}", is_x86_feature_detected!("tbm")); - println!("popcnt: {:?}", is_x86_feature_detected!("popcnt")); - println!("lzcnt: {:?}", is_x86_feature_detected!("lzcnt")); - println!("fxsr: {:?}", is_x86_feature_detected!("fxsr")); - println!("xsave: {:?}", is_x86_feature_detected!("xsave")); - println!("xsaveopt: {:?}", is_x86_feature_detected!("xsaveopt")); - println!("xsaves: {:?}", is_x86_feature_detected!("xsaves")); - println!("xsavec: {:?}", is_x86_feature_detected!("xsavec")); - println!("cmpxchg16b: {:?}", is_x86_feature_detected!("cmpxchg16b")); - println!("adx: {:?}", is_x86_feature_detected!("adx")); - println!("rtm: {:?}", is_x86_feature_detected!("rtm")); - } - - #[test] - fn compare_with_cupid() { - let information = cupid::master().unwrap(); - assert_eq!(is_x86_feature_detected!("aes"), information.aesni()); - assert_eq!( - is_x86_feature_detected!("pclmulqdq"), - information.pclmulqdq() - ); - assert_eq!(is_x86_feature_detected!("rdrand"), information.rdrand()); - assert_eq!(is_x86_feature_detected!("rdseed"), information.rdseed()); - assert_eq!(is_x86_feature_detected!("tsc"), information.tsc()); - assert_eq!(is_x86_feature_detected!("sse"), information.sse()); - assert_eq!(is_x86_feature_detected!("sse2"), information.sse2()); - assert_eq!(is_x86_feature_detected!("sse3"), information.sse3()); - assert_eq!(is_x86_feature_detected!("ssse3"), information.ssse3()); - assert_eq!(is_x86_feature_detected!("sse4.1"), information.sse4_1()); - assert_eq!(is_x86_feature_detected!("sse4.2"), information.sse4_2()); - assert_eq!(is_x86_feature_detected!("sse4a"), information.sse4a()); - assert_eq!(is_x86_feature_detected!("sha"), information.sha()); - assert_eq!(is_x86_feature_detected!("avx"), information.avx()); - assert_eq!(is_x86_feature_detected!("avx2"), information.avx2()); - assert_eq!(is_x86_feature_detected!("avx512f"), information.avx512f()); - assert_eq!(is_x86_feature_detected!("avx512cd"), information.avx512cd()); - assert_eq!(is_x86_feature_detected!("avx512er"), information.avx512er()); - assert_eq!(is_x86_feature_detected!("avx512pf"), information.avx512pf()); - assert_eq!(is_x86_feature_detected!("avx512bw"), information.avx512bw()); - assert_eq!(is_x86_feature_detected!("avx512dq"), information.avx512dq()); - assert_eq!(is_x86_feature_detected!("avx512vl"), information.avx512vl()); - assert_eq!( - is_x86_feature_detected!("avx512ifma"), - information.avx512_ifma() - ); - assert_eq!( - is_x86_feature_detected!("avx512vbmi"), - information.avx512_vbmi() - ); - assert_eq!( - is_x86_feature_detected!("avx512vpopcntdq"), - information.avx512_vpopcntdq() - ); - assert_eq!(is_x86_feature_detected!("fma"), information.fma()); - assert_eq!(is_x86_feature_detected!("bmi1"), information.bmi1()); - assert_eq!(is_x86_feature_detected!("bmi2"), information.bmi2()); - assert_eq!(is_x86_feature_detected!("popcnt"), information.popcnt()); - assert_eq!(is_x86_feature_detected!("abm"), information.lzcnt()); - assert_eq!(is_x86_feature_detected!("tbm"), information.tbm()); - assert_eq!(is_x86_feature_detected!("lzcnt"), information.lzcnt()); - assert_eq!(is_x86_feature_detected!("xsave"), information.xsave()); - assert_eq!(is_x86_feature_detected!("xsaveopt"), information.xsaveopt()); - assert_eq!( - is_x86_feature_detected!("xsavec"), - information.xsavec_and_xrstor() - ); - assert_eq!( - is_x86_feature_detected!("xsaves"), - information.xsaves_xrstors_and_ia32_xss() - ); - assert_eq!( - is_x86_feature_detected!("cmpxchg16b"), - information.cmpxchg16b(), - ); - assert_eq!(is_x86_feature_detected!("adx"), information.adx(),); - assert_eq!(is_x86_feature_detected!("rtm"), information.rtm(),); - } -} diff --git a/crates/std_detect/src/lib.rs b/crates/std_detect/src/lib.rs index 7737719c3b..bb70baaf61 100644 --- a/crates/std_detect/src/lib.rs +++ b/crates/std_detect/src/lib.rs @@ -24,12 +24,12 @@ extern crate cfg_if; cfg_if! { - if #[cfg(feature = "std_detect_file_io")] { + if #[cfg(any(feature = "std_detect_file_io", feature = "std_detect_env_override"))] { #[cfg_attr(test, macro_use(println))] extern crate std; #[allow(unused_imports)] - use std::{arch, fs, io, mem, sync}; + use std::{arch, env, fs, io, mem, sync}; } else { #[cfg(test)] #[macro_use(println)] diff --git a/crates/std_detect/tests/features.rs b/crates/std_detect/tests/features.rs new file mode 100644 index 0000000000..7fe81d3e7f --- /dev/null +++ b/crates/std_detect/tests/features.rs @@ -0,0 +1,13 @@ +#![feature(stdsimd)] +#![feature(stdsimd_internal)] + +extern crate std_detect; + +use std_detect::detect::{features, Feature}; + +#[test] +fn features_roundtrip() { + for (f, _) in features() { + let _ = Feature::from_str(f).unwrap(); + } +} diff --git a/crates/std_detect/tests/x86-specific.rs b/crates/std_detect/tests/x86-specific.rs new file mode 100644 index 0000000000..cb51649725 --- /dev/null +++ b/crates/std_detect/tests/x86-specific.rs @@ -0,0 +1,140 @@ +#![feature(stdsimd)] + +extern crate cupid; +#[macro_use] +extern crate std_detect; + +#[test] +fn dump() { + println!("aes: {:?}", is_x86_feature_detected!("aes")); + println!("pclmulqdq: {:?}", is_x86_feature_detected!("pclmulqdq")); + println!("rdrand: {:?}", is_x86_feature_detected!("rdrand")); + println!("rdseed: {:?}", is_x86_feature_detected!("rdseed")); + println!("tsc: {:?}", is_x86_feature_detected!("tsc")); + println!("sse: {:?}", is_x86_feature_detected!("sse")); + println!("sse2: {:?}", is_x86_feature_detected!("sse2")); + println!("sse3: {:?}", is_x86_feature_detected!("sse3")); + println!("ssse3: {:?}", is_x86_feature_detected!("ssse3")); + println!("sse4.1: {:?}", is_x86_feature_detected!("sse4.1")); + println!("sse4.2: {:?}", is_x86_feature_detected!("sse4.2")); + println!("sse4a: {:?}", is_x86_feature_detected!("sse4a")); + println!("sha: {:?}", is_x86_feature_detected!("sha")); + println!("avx: {:?}", is_x86_feature_detected!("avx")); + println!("avx2: {:?}", is_x86_feature_detected!("avx2")); + println!("avx512f {:?}", is_x86_feature_detected!("avx512f")); + println!("avx512cd {:?}", is_x86_feature_detected!("avx512cd")); + println!("avx512er {:?}", is_x86_feature_detected!("avx512er")); + println!("avx512pf {:?}", is_x86_feature_detected!("avx512pf")); + println!("avx512bw {:?}", is_x86_feature_detected!("avx512bw")); + println!("avx512dq {:?}", is_x86_feature_detected!("avx512dq")); + println!("avx512vl {:?}", is_x86_feature_detected!("avx512vl")); + println!("avx512_ifma {:?}", is_x86_feature_detected!("avx512ifma")); + println!("avx512_vbmi {:?}", is_x86_feature_detected!("avx512vbmi")); + println!( + "avx512_vpopcntdq {:?}", + is_x86_feature_detected!("avx512vpopcntdq") + ); + println!("fma: {:?}", is_x86_feature_detected!("fma")); + println!("abm: {:?}", is_x86_feature_detected!("abm")); + println!("bmi: {:?}", is_x86_feature_detected!("bmi1")); + println!("bmi2: {:?}", is_x86_feature_detected!("bmi2")); + println!("tbm: {:?}", is_x86_feature_detected!("tbm")); + println!("popcnt: {:?}", is_x86_feature_detected!("popcnt")); + println!("lzcnt: {:?}", is_x86_feature_detected!("lzcnt")); + println!("fxsr: {:?}", is_x86_feature_detected!("fxsr")); + println!("xsave: {:?}", is_x86_feature_detected!("xsave")); + println!("xsaveopt: {:?}", is_x86_feature_detected!("xsaveopt")); + println!("xsaves: {:?}", is_x86_feature_detected!("xsaves")); + println!("xsavec: {:?}", is_x86_feature_detected!("xsavec")); + println!("cmpxchg16b: {:?}", is_x86_feature_detected!("cmpxchg16b")); + println!("adx: {:?}", is_x86_feature_detected!("adx")); + println!("rtm: {:?}", is_x86_feature_detected!("rtm")); +} + +#[cfg(feature = "std_detect_env_override")] +#[test] +fn env_override_no_avx() { + if let Ok(disable) = std::env::var("RUST_STD_DETECT_UNSTABLE") { + let information = cupid::master().unwrap(); + for d in disable.split(" ") { + match d { + "avx" => { + if information.avx() { + assert_ne!(is_x86_feature_detected!("avx"), information.avx()) + } + } + "avx2" => { + if information.avx2() { + assert_ne!(is_x86_feature_detected!("avx2"), information.avx2()) + } + } + _ => {} + } + } + } +} + +#[test] +fn compare_with_cupid() { + let information = cupid::master().unwrap(); + assert_eq!(is_x86_feature_detected!("aes"), information.aesni()); + assert_eq!( + is_x86_feature_detected!("pclmulqdq"), + information.pclmulqdq() + ); + assert_eq!(is_x86_feature_detected!("rdrand"), information.rdrand()); + assert_eq!(is_x86_feature_detected!("rdseed"), information.rdseed()); + assert_eq!(is_x86_feature_detected!("tsc"), information.tsc()); + assert_eq!(is_x86_feature_detected!("sse"), information.sse()); + assert_eq!(is_x86_feature_detected!("sse2"), information.sse2()); + assert_eq!(is_x86_feature_detected!("sse3"), information.sse3()); + assert_eq!(is_x86_feature_detected!("ssse3"), information.ssse3()); + assert_eq!(is_x86_feature_detected!("sse4.1"), information.sse4_1()); + assert_eq!(is_x86_feature_detected!("sse4.2"), information.sse4_2()); + assert_eq!(is_x86_feature_detected!("sse4a"), information.sse4a()); + assert_eq!(is_x86_feature_detected!("sha"), information.sha()); + assert_eq!(is_x86_feature_detected!("avx"), information.avx()); + assert_eq!(is_x86_feature_detected!("avx2"), information.avx2()); + assert_eq!(is_x86_feature_detected!("avx512f"), information.avx512f()); + assert_eq!(is_x86_feature_detected!("avx512cd"), information.avx512cd()); + assert_eq!(is_x86_feature_detected!("avx512er"), information.avx512er()); + assert_eq!(is_x86_feature_detected!("avx512pf"), information.avx512pf()); + assert_eq!(is_x86_feature_detected!("avx512bw"), information.avx512bw()); + assert_eq!(is_x86_feature_detected!("avx512dq"), information.avx512dq()); + assert_eq!(is_x86_feature_detected!("avx512vl"), information.avx512vl()); + assert_eq!( + is_x86_feature_detected!("avx512ifma"), + information.avx512_ifma() + ); + assert_eq!( + is_x86_feature_detected!("avx512vbmi"), + information.avx512_vbmi() + ); + assert_eq!( + is_x86_feature_detected!("avx512vpopcntdq"), + information.avx512_vpopcntdq() + ); + assert_eq!(is_x86_feature_detected!("fma"), information.fma()); + assert_eq!(is_x86_feature_detected!("bmi1"), information.bmi1()); + assert_eq!(is_x86_feature_detected!("bmi2"), information.bmi2()); + assert_eq!(is_x86_feature_detected!("popcnt"), information.popcnt()); + assert_eq!(is_x86_feature_detected!("abm"), information.lzcnt()); + assert_eq!(is_x86_feature_detected!("tbm"), information.tbm()); + assert_eq!(is_x86_feature_detected!("lzcnt"), information.lzcnt()); + assert_eq!(is_x86_feature_detected!("xsave"), information.xsave()); + assert_eq!(is_x86_feature_detected!("xsaveopt"), information.xsaveopt()); + assert_eq!( + is_x86_feature_detected!("xsavec"), + information.xsavec_and_xrstor() + ); + assert_eq!( + is_x86_feature_detected!("xsaves"), + information.xsaves_xrstors_and_ia32_xss() + ); + assert_eq!( + is_x86_feature_detected!("cmpxchg16b"), + information.cmpxchg16b(), + ); + assert_eq!(is_x86_feature_detected!("adx"), information.adx(),); + assert_eq!(is_x86_feature_detected!("rtm"), information.rtm(),); +}