Skip to content

Env override support #808

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions ci/azure.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
5 changes: 3 additions & 2 deletions crates/std_detect/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" ]
std_detect_dlsym_getauxval = [ "libc" ]
std_detect_env_override = []
47 changes: 42 additions & 5 deletions crates/std_detect/src/detect/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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!"
Expand All @@ -54,15 +60,24 @@ 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!"
);
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.
Expand Down Expand Up @@ -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()`.
Expand All @@ -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<F>(bit: u32, f: F) -> bool
where
F: FnOnce() -> Initializer,
{
if CACHE.is_uninitialized() {
CACHE.initialize(f());
initialize(f());
}
CACHE.test(bit)
}
6 changes: 6 additions & 0 deletions crates/std_detect/src/detect/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ macro_rules! features {
Feature::_last => unreachable!(),
}
}
pub fn from_str(s: &str) -> Result<Feature, ()> {
match s {
$($feature_lit => Ok(Feature::$feature),)*
_ => Err(())
}
}
}

/// Each function performs run-time feature detection for a single
Expand Down
7 changes: 7 additions & 0 deletions crates/std_detect/src/detect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ cfg_if! {
}
#[doc(hidden)]
pub mod __is_feature_detected {}

impl Feature {
#[doc(hidden)]
pub fn from_str(_s: &str) -> Result<Feature, ()> { Err<()> }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

syntax error

#[doc(hidden)]
pub fn to_str(self) -> &'static str { "" }
}
}
}
}
Expand Down
117 changes: 0 additions & 117 deletions crates/std_detect/src/detect/os/x86.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),);
}
}
4 changes: 2 additions & 2 deletions crates/std_detect/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
13 changes: 13 additions & 0 deletions crates/std_detect/tests/features.rs
Original file line number Diff line number Diff line change
@@ -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();
}
}
Loading