diff --git a/ci/azure-install-rust.yml b/ci/azure-install-rust.yml index feb06588f3..65743d1d46 100644 --- a/ci/azure-install-rust.yml +++ b/ci/azure-install-rust.yml @@ -17,7 +17,7 @@ steps: - script: | @echo on if not defined TOOLCHAIN set TOOLCHAIN=nightly - rustup update %TOOLCHAIN%-%TARGET% + rustup update --no-self-update %TOOLCHAIN%-%TARGET% rustup default %TOOLCHAIN%-%TARGET% displayName: Install rust (windows) condition: eq( variables['Agent.OS'], 'Windows_NT' ) diff --git a/crates/core_arch/src/mips/msa.rs b/crates/core_arch/src/mips/msa.rs index f93bcdbae7..29009b5d7c 100644 --- a/crates/core_arch/src/mips/msa.rs +++ b/crates/core_arch/src/mips/msa.rs @@ -13531,7 +13531,7 @@ mod tests { #[simd_test(enable = "msa")] unsafe fn test_msa_frint_w() { #[rustfmt::skip] - let a = f32x4::new(2.6, -2.7, 1.3, -1.7);; + let a = f32x4::new(2.6, -2.7, 1.3, -1.7); #[rustfmt::skip] let r = f32x4::new(3.0, -3.0, 1.0, -2.0); @@ -13551,7 +13551,7 @@ mod tests { #[simd_test(enable = "msa")] unsafe fn test_msa_frcp_w() { #[rustfmt::skip] - let a = f32x4::new(2.6, -2.7, 1.3, -1.7);; + let a = f32x4::new(2.6, -2.7, 1.3, -1.7); #[rustfmt::skip] let r = f32x4::new( 0.3846154, -0.37037036, @@ -13574,7 +13574,7 @@ mod tests { #[simd_test(enable = "msa")] unsafe fn test_msa_frsqrt_w() { #[rustfmt::skip] - let a = f32x4::new(2.6, 2.7, 1.3, 1.7);; + let a = f32x4::new(2.6, 2.7, 1.3, 1.7); #[rustfmt::skip] let r = f32x4::new( 0.6201737, 0.6085806, diff --git a/crates/std_detect/src/detect/arch/aarch64.rs b/crates/std_detect/src/detect/arch/aarch64.rs index ebae2bd285..154207e5ad 100644 --- a/crates/std_detect/src/detect/arch/aarch64.rs +++ b/crates/std_detect/src/detect/arch/aarch64.rs @@ -1,106 +1,36 @@ //! Aarch64 run-time features. -/// Checks if `aarch64` feature is enabled. -#[macro_export] -#[unstable(feature = "stdsimd", issue = "27731")] -#[allow_internal_unstable(stdsimd_internal,stdsimd)] -macro_rules! is_aarch64_feature_detected { - ("neon") => { - // FIXME: this should be removed once we rename Aarch64 neon to asimd - cfg!(target_feature = "neon") || - $crate::detect::check_for($crate::detect::Feature::asimd) - }; - ("asimd") => { - cfg!(target_feature = "neon") || - $crate::detect::check_for($crate::detect::Feature::asimd) - }; - ("pmull") => { - cfg!(target_feature = "pmull") || - $crate::detect::check_for($crate::detect::Feature::pmull) - }; - ("fp") => { - cfg!(target_feature = "fp") || - $crate::detect::check_for($crate::detect::Feature::fp) - }; - ("fp16") => { - cfg!(target_feature = "fp16") || - $crate::detect::check_for($crate::detect::Feature::fp16) - }; - ("sve") => { - cfg!(target_feature = "sve") || - $crate::detect::check_for($crate::detect::Feature::sve) - }; - ("crc") => { - cfg!(target_feature = "crc") || - $crate::detect::check_for($crate::detect::Feature::crc) - }; - ("crypto") => { - cfg!(target_feature = "crypto") || - $crate::detect::check_for($crate::detect::Feature::crypto) - }; - ("lse") => { - cfg!(target_feature = "lse") || - $crate::detect::check_for($crate::detect::Feature::lse) - }; - ("rdm") => { - cfg!(target_feature = "rdm") || - $crate::detect::check_for($crate::detect::Feature::rdm) - }; - ("rcpc") => { - cfg!(target_feature = "rcpc") || - $crate::detect::check_for($crate::detect::Feature::rcpc) - }; - ("dotprod") => { - cfg!(target_feature = "dotprod") || - $crate::detect::check_for($crate::detect::Feature::dotprod) - }; - ("ras") => { - compile_error!("\"ras\" feature cannot be detected at run-time") - }; - ("v8.1a") => { - compile_error!("\"v8.1a\" feature cannot be detected at run-time") - }; - ("v8.2a") => { - compile_error!("\"v8.2a\" feature cannot be detected at run-time") - }; - ("v8.3a") => { - compile_error!("\"v8.3a\" feature cannot be detected at run-time") - }; - ($t:tt,) => { - is_aarch64_feature_detected!($t); - }; - ($t:tt) => { compile_error!(concat!("unknown aarch64 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)] -#[unstable(feature = "stdsimd_internal", issue = "0")] -pub enum Feature { +features! { + @TARGET: aarch64; + @MACRO_NAME: is_aarch64_feature_detected; + @MACRO_ATTRS: + /// Checks if `aarch64` feature is enabled. + #[unstable(feature = "stdsimd", issue = "27731")] + @BIND_FEATURE_NAME: "asimd"; "neon"; + @NO_RUNTIME_DETECTION: "ras"; + @NO_RUNTIME_DETECTION: "v8.1a"; + @NO_RUNTIME_DETECTION: "v8.2a"; + @NO_RUNTIME_DETECTION: "v8.3a"; + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] asimd: "neon"; /// ARM Advanced SIMD (ASIMD) - asimd, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] pmull: "pmull"; /// Polynomial Multiply - pmull, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] fp: "fp"; /// Floating point support - fp, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] fp16: "fp16"; /// Half-float support. - fp16, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] sve: "sve"; /// Scalable Vector Extension (SVE) - sve, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] crc: "crc"; /// CRC32 (Cyclic Redundancy Check) - crc, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] crypto: "crypto"; /// Crypto: AES + PMULL + SHA1 + SHA2 - crypto, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] lse: "lse"; /// Atomics (Large System Extension) - lse, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] rdm: "rdm"; /// Rounding Double Multiply (ASIMDRDM) - rdm, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] rcpc: "rcpc"; /// Release consistent Processor consistent (RcPc) - rcpc, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] dotprod: "dotprod"; /// Vector Dot-Product (ASIMDDP) - dotprod, } diff --git a/crates/std_detect/src/detect/arch/arm.rs b/crates/std_detect/src/detect/arch/arm.rs index b2626bf292..02bf654945 100644 --- a/crates/std_detect/src/detect/arch/arm.rs +++ b/crates/std_detect/src/detect/arch/arm.rs @@ -1,39 +1,17 @@ //! Run-time feature detection on ARM Aarch32. -/// Checks if `arm` feature is enabled. -#[macro_export] -#[unstable(feature = "stdsimd", issue = "27731")] -#[allow_internal_unstable(stdsimd_internal,stdsimd)] -macro_rules! is_arm_feature_detected { - ("neon") => { - cfg!(target_feature = "neon") || - $crate::detect::check_for($crate::detect::Feature::neon) - }; - ("pmull") => { - cfg!(target_feature = "pmull") || - $crate::detect::check_for($crate::detect::Feature::pmull) - }; - ("v7") => { compile_error!("\"v7\" feature cannot be detected at run-time") }; - ("vfp2") => { compile_error!("\"vfp2\" feature cannot be detected at run-time") }; - ("vfp3") => { compile_error!("\"vfp3\" feature cannot be detected at run-time") }; - ("vfp4") => { compile_error!("\"vfp4\" feature cannot be detected at run-time") }; - ($t:tt,) => { - is_arm_feature_detected!($t); - }; - ($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)] -#[unstable(feature = "stdsimd_internal", issue = "0")] -pub enum Feature { +features! { + @TARGET: arm; + @MACRO_NAME: is_arm_feature_detected; + @MACRO_ATTRS: + /// Checks if `arm` feature is enabled. + #[unstable(feature = "stdsimd", issue = "27731")] + @NO_RUNTIME_DETECTION: "v7"; + @NO_RUNTIME_DETECTION: "vfp2"; + @NO_RUNTIME_DETECTION: "vfp3"; + @NO_RUNTIME_DETECTION: "vfp4"; + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] neon: "neon"; /// ARM Advanced SIMD (NEON) - Aarch32 - neon, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] pmull: "pmull"; /// Polynomial Multiply - pmull, } diff --git a/crates/std_detect/src/detect/arch/mips.rs b/crates/std_detect/src/detect/arch/mips.rs index f4381b811c..ada81b83ec 100644 --- a/crates/std_detect/src/detect/arch/mips.rs +++ b/crates/std_detect/src/detect/arch/mips.rs @@ -1,29 +1,11 @@ //! Run-time feature detection on MIPS. -/// Checks if `mips` feature is enabled. -#[macro_export] -#[unstable(feature = "stdsimd", issue = "27731")] -#[allow_internal_unstable(stdsimd_internal,stdsimd)] -macro_rules! is_mips_feature_detected { - ("msa") => { - cfg!(target_feature = "msa") || - $crate::detect::check_for($crate::detect::Feature::msa) - }; - ($t:tt,) => { - is_mips_feature_detected!($t); - }; - ($t:tt) => { compile_error!(concat!("unknown mips target feature: ", $t)) }; -} - -/// MIPS 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)] -#[unstable(feature = "stdsimd_internal", issue = "0")] -pub enum Feature { +features! { + @TARGET: mips; + @MACRO_NAME: is_mips_feature_detected; + @MACRO_ATTRS: + /// Checks if `mips` feature is enabled. + #[unstable(feature = "stdsimd", issue = "27731")] + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] msa: "msa"; /// MIPS SIMD Architecture (MSA) - msa, } diff --git a/crates/std_detect/src/detect/arch/mips64.rs b/crates/std_detect/src/detect/arch/mips64.rs index 2663bc68ba..6a0bb159ba 100644 --- a/crates/std_detect/src/detect/arch/mips64.rs +++ b/crates/std_detect/src/detect/arch/mips64.rs @@ -1,29 +1,11 @@ //! Run-time feature detection on MIPS64. -/// Checks if `mips64` feature is enabled. -#[macro_export] -#[unstable(feature = "stdsimd", issue = "27731")] -#[allow_internal_unstable(stdsimd_internal,stdsimd)] -macro_rules! is_mips64_feature_detected { - ("msa") => { - cfg!(target_feature = "msa") || - $crate::detect::check_for($crate::detect::Feature::msa) - }; - ($t:tt,) => { - is_mips64_feature_detected!($t); - }; - ($t:tt) => { compile_error!(concat!("unknown mips64 target feature: ", $t)) }; -} - -/// MIPS64 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)] -#[unstable(feature = "stdsimd_internal", issue = "0")] -pub enum Feature { +features! { + @TARGET: mips64; + @MACRO_NAME: is_mips64_feature_detected; + @MACRO_ATTRS: + /// Checks if `mips64` feature is enabled. + #[unstable(feature = "stdsimd", issue = "27731")] + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] msa: "msa"; /// MIPS SIMD Architecture (MSA) - msa, } diff --git a/crates/std_detect/src/detect/arch/powerpc.rs b/crates/std_detect/src/detect/arch/powerpc.rs index a342dc1aac..44bd7f337f 100644 --- a/crates/std_detect/src/detect/arch/powerpc.rs +++ b/crates/std_detect/src/detect/arch/powerpc.rs @@ -1,42 +1,15 @@ //! Run-time feature detection on PowerPC. -/// Checks if `powerpc` feature is enabled. -#[macro_export] -#[unstable(feature = "stdsimd", issue = "27731")] -#[allow_internal_unstable(stdsimd_internal,stdsimd)] -macro_rules! is_powerpc_feature_detected { - ("altivec") => { - cfg!(target_feature = "altivec") || - $crate::detect::check_for($crate::detect::Feature::altivec) - }; - ("vsx") => { - cfg!(target_feature = "vsx") || - $crate::detect::check_for($crate::detect::Feature::vsx) - }; - ("power8") => { - cfg!(target_feature = "power8") || - $crate::detect::check_for($crate::detect::Feature::power8) - }; - ($t:tt,) => { - is_powerpc_feature_detected!($t); - }; - ($t:tt) => { compile_error!(concat!("unknown powerpc target feature: ", $t)) }; -} - - -/// PowerPC 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)] -#[unstable(feature = "stdsimd_internal", issue = "0")] -pub enum Feature { +features! { + @TARGET: powerpc; + @MACRO_NAME: is_powerpc_feature_detected; + @MACRO_ATTRS: + /// Checks if `powerpc` feature is enabled. + #[unstable(feature = "stdsimd", issue = "27731")] + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] altivec: "altivec"; /// Altivec - altivec, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] vsx: "vsx"; /// VSX - vsx, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] power8: "power8"; /// Power8 - power8, } diff --git a/crates/std_detect/src/detect/arch/powerpc64.rs b/crates/std_detect/src/detect/arch/powerpc64.rs index 2e82c56925..17e4d958bf 100644 --- a/crates/std_detect/src/detect/arch/powerpc64.rs +++ b/crates/std_detect/src/detect/arch/powerpc64.rs @@ -1,42 +1,15 @@ //! Run-time feature detection on PowerPC64. -/// Checks if `powerpc64` feature is enabled. -#[macro_export] -#[unstable(feature = "stdsimd", issue = "27731")] -#[allow_internal_unstable(stdsimd_internal,stdsimd)] -macro_rules! is_powerpc64_feature_detected { - ("altivec") => { - cfg!(target_feature = "altivec") || - $crate::detect::check_for($crate::detect::Feature::altivec) - }; - ("vsx") => { - cfg!(target_feature = "vsx") || - $crate::detect::check_for($crate::detect::Feature::vsx) - }; - ("power8") => { - cfg!(target_feature = "power8") || - $crate::detect::check_for($crate::detect::Feature::power8) - }; - ($t:tt,) => { - is_powerpc64_feature_detected!($t); - }; - ($t:tt) => { compile_error!(concat!("unknown powerpc64 target feature: ", $t)) }; -} - - -/// PowerPC64 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)] -#[unstable(feature = "stdsimd_internal", issue = "0")] -pub enum Feature { +features! { + @TARGET: powerpc64; + @MACRO_NAME: is_powerpc64_feature_detected; + @MACRO_ATTRS: + /// Checks if `powerpc` feature is enabled. + #[unstable(feature = "stdsimd", issue = "27731")] + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] altivec: "altivec"; /// Altivec - altivec, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] vsx: "vsx"; /// VSX - vsx, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] power8: "power8"; /// Power8 - power8, } diff --git a/crates/std_detect/src/detect/arch/x86.rs b/crates/std_detect/src/detect/arch/x86.rs index 50d5cfa87c..ae0bebdae5 100644 --- a/crates/std_detect/src/detect/arch/x86.rs +++ b/crates/std_detect/src/detect/arch/x86.rs @@ -15,334 +15,154 @@ //! in a global `AtomicUsize` variable. The query is performed by just checking //! whether the feature bit in this global variable is set or cleared. -/// A macro to test at *runtime* whether a CPU feature is available on -/// x86/x86-64 platforms. -/// -/// This macro is provided in the standard library and will detect at runtime -/// whether the specified CPU feature is detected. This does **not** resolve at -/// compile time unless the specified feature is already enabled for the entire -/// crate. Runtime detection currently relies mostly on the `cpuid` instruction. -/// -/// This macro only takes one argument which is a string literal of the feature -/// being tested for. The feature names supported are the lowercase versions of -/// the ones defined by Intel in [their documentation][docs]. -/// -/// ## Supported arguments -/// -/// This macro supports the same names that `#[target_feature]` supports. Unlike -/// `#[target_feature]`, however, this macro does not support names separated -/// with a comma. Instead testing for multiple features must be done through -/// separate macro invocations for now. -/// -/// Supported arguments are: -/// -/// * `"aes"` -/// * `"pclmulqdq"` -/// * `"rdrand"` -/// * `"rdseed"` -/// * `"tsc"` -/// * `"mmx"` -/// * `"sse"` -/// * `"sse2"` -/// * `"sse3"` -/// * `"ssse3"` -/// * `"sse4.1"` -/// * `"sse4.2"` -/// * `"sse4a"` -/// * `"sha"` -/// * `"avx"` -/// * `"avx2"` -/// * `"avx512f"` -/// * `"avx512cd"` -/// * `"avx512er"` -/// * `"avx512pf"` -/// * `"avx512bw"` -/// * `"avx512dq"` -/// * `"avx512vl"` -/// * `"avx512ifma"` -/// * `"avx512vbmi"` -/// * `"avx512vpopcntdq"` -/// * `"f16c"` -/// * `"fma"` -/// * `"bmi1"` -/// * `"bmi2"` -/// * `"abm"` -/// * `"lzcnt"` -/// * `"tbm"` -/// * `"popcnt"` -/// * `"fxsr"` -/// * `"xsave"` -/// * `"xsaveopt"` -/// * `"xsaves"` -/// * `"xsavec"` -/// * `"adx"` -/// * `"rtm"` -/// -/// [docs]: https://software.intel.com/sites/landingpage/IntrinsicsGuide -#[macro_export] -#[stable(feature = "simd_x86", since = "1.27.0")] -#[allow_internal_unstable(stdsimd_internal,stdsimd)] -macro_rules! is_x86_feature_detected { - ("aes") => { - cfg!(target_feature = "aes") || $crate::detect::check_for( - $crate::detect::Feature::aes) }; - ("pclmulqdq") => { - cfg!(target_feature = "pclmulqdq") || $crate::detect::check_for( - $crate::detect::Feature::pclmulqdq) }; - ("rdrand") => { - cfg!(target_feature = "rdrand") || $crate::detect::check_for( - $crate::detect::Feature::rdrand) }; - ("rdseed") => { - cfg!(target_feature = "rdseed") || $crate::detect::check_for( - $crate::detect::Feature::rdseed) }; - ("tsc") => { - cfg!(target_feature = "tsc") || $crate::detect::check_for( - $crate::detect::Feature::tsc) }; - ("mmx") => { - cfg!(target_feature = "mmx") || $crate::detect::check_for( - $crate::detect::Feature::mmx) }; - ("sse") => { - cfg!(target_feature = "sse") || $crate::detect::check_for( - $crate::detect::Feature::sse) }; - ("sse2") => { - cfg!(target_feature = "sse2") || $crate::detect::check_for( - $crate::detect::Feature::sse2) - }; - ("sse3") => { - cfg!(target_feature = "sse3") || $crate::detect::check_for( - $crate::detect::Feature::sse3) - }; - ("ssse3") => { - cfg!(target_feature = "ssse3") || $crate::detect::check_for( - $crate::detect::Feature::ssse3) - }; - ("sse4.1") => { - cfg!(target_feature = "sse4.1") || $crate::detect::check_for( - $crate::detect::Feature::sse4_1) - }; - ("sse4.2") => { - cfg!(target_feature = "sse4.2") || $crate::detect::check_for( - $crate::detect::Feature::sse4_2) - }; - ("sse4a") => { - cfg!(target_feature = "sse4a") || $crate::detect::check_for( - $crate::detect::Feature::sse4a) - }; - ("sha") => { - cfg!(target_feature = "sha") || $crate::detect::check_for( - $crate::detect::Feature::sha) - }; - ("avx") => { - cfg!(target_feature = "avx") || $crate::detect::check_for( - $crate::detect::Feature::avx) - }; - ("avx2") => { - cfg!(target_feature = "avx2") || $crate::detect::check_for( - $crate::detect::Feature::avx2) - }; - ("avx512f") => { - cfg!(target_feature = "avx512f") || $crate::detect::check_for( - $crate::detect::Feature::avx512f) - }; - ("avx512cd") => { - cfg!(target_feature = "avx512cd") || $crate::detect::check_for( - $crate::detect::Feature::avx512cd) - }; - ("avx512er") => { - cfg!(target_feature = "avx512er") || $crate::detect::check_for( - $crate::detect::Feature::avx512er) - }; - ("avx512pf") => { - cfg!(target_feature = "avx512pf") || $crate::detect::check_for( - $crate::detect::Feature::avx512pf) - }; - ("avx512bw") => { - cfg!(target_feature = "avx512bw") || $crate::detect::check_for( - $crate::detect::Feature::avx512bw) - }; - ("avx512dq") => { - cfg!(target_feature = "avx512dq") || $crate::detect::check_for( - $crate::detect::Feature::avx512dq) - }; - ("avx512vl") => { - cfg!(target_Feature = "avx512vl") || $crate::detect::check_for( - $crate::detect::Feature::avx512vl) - }; - ("avx512ifma") => { - cfg!(target_feature = "avx512ifma") || $crate::detect::check_for( - $crate::detect::Feature::avx512_ifma) - }; - ("avx512vbmi") => { - cfg!(target_feature = "avx512vbmi") || $crate::detect::check_for( - $crate::detect::Feature::avx512_vbmi) - }; - ("avx512vpopcntdq") => { - cfg!(target_feature = "avx512vpopcntdq") || $crate::detect::check_for( - $crate::detect::Feature::avx512_vpopcntdq) - }; - ("f16c") => { - cfg!(target_feature = "f16c") || $crate::detect::check_for( - $crate::detect::Feature::f16c) - }; - ("fma") => { - cfg!(target_feature = "fma") || $crate::detect::check_for( - $crate::detect::Feature::fma) - }; - ("bmi1") => { - cfg!(target_feature = "bmi1") || $crate::detect::check_for( - $crate::detect::Feature::bmi) - }; - ("bmi2") => { - cfg!(target_feature = "bmi2") || $crate::detect::check_for( - $crate::detect::Feature::bmi2) - }; - ("abm") => { - cfg!(target_feature = "abm") || $crate::detect::check_for( - $crate::detect::Feature::abm) - }; - ("lzcnt") => { - cfg!(target_feature = "lzcnt") || $crate::detect::check_for( - $crate::detect::Feature::abm) - }; - ("tbm") => { - cfg!(target_feature = "tbm") || $crate::detect::check_for( - $crate::detect::Feature::tbm) - }; - ("popcnt") => { - cfg!(target_feature = "popcnt") || $crate::detect::check_for( - $crate::detect::Feature::popcnt) - }; - ("fxsr") => { - cfg!(target_feature = "fxsr") || $crate::detect::check_for( - $crate::detect::Feature::fxsr) - }; - ("xsave") => { - cfg!(target_feature = "xsave") || $crate::detect::check_for( - $crate::detect::Feature::xsave) - }; - ("xsaveopt") => { - cfg!(target_feature = "xsaveopt") || $crate::detect::check_for( - $crate::detect::Feature::xsaveopt) - }; - ("xsaves") => { - cfg!(target_feature = "xsaves") || $crate::detect::check_for( - $crate::detect::Feature::xsaves) - }; - ("xsavec") => { - cfg!(target_feature = "xsavec") || $crate::detect::check_for( - $crate::detect::Feature::xsavec) - }; - ("cmpxchg16b") => { - cfg!(target_feature = "cmpxchg16b") || $crate::detect::check_for( - $crate::detect::Feature::cmpxchg16b) - }; - ("adx") => { - cfg!(target_feature = "adx") || $crate::detect::check_for( - $crate::detect::Feature::adx) - }; - ("rtm") => { - cfg!(target_feature = "rtm") || $crate::detect::check_for( - $crate::detect::Feature::rtm) - }; - ($t:tt,) => { - is_x86_feature_detected!($t); - }; - ($t:tt) => { - compile_error!(concat!("unknown target feature: ", $t)) - }; -} - -/// X86 CPU Feature enum. Each variant denotes a position in a bitset for a -/// particular feature. -/// -/// This is an unstable implementation detail subject to change. -#[allow(non_camel_case_types)] -#[repr(u8)] -#[doc(hidden)] -#[unstable(feature = "stdsimd_internal", issue = "0")] -pub enum Feature { +features! { + @TARGET: x86; + @MACRO_NAME: is_x86_feature_detected; + @MACRO_ATTRS: + /// A macro to test at *runtime* whether a CPU feature is available on + /// x86/x86-64 platforms. + /// + /// This macro is provided in the standard library and will detect at runtime + /// whether the specified CPU feature is detected. This does **not** resolve at + /// compile time unless the specified feature is already enabled for the entire + /// crate. Runtime detection currently relies mostly on the `cpuid` instruction. + /// + /// This macro only takes one argument which is a string literal of the feature + /// being tested for. The feature names supported are the lowercase versions of + /// the ones defined by Intel in [their documentation][docs]. + /// + /// ## Supported arguments + /// + /// This macro supports the same names that `#[target_feature]` supports. Unlike + /// `#[target_feature]`, however, this macro does not support names separated + /// with a comma. Instead testing for multiple features must be done through + /// separate macro invocations for now. + /// + /// Supported arguments are: + /// + /// * `"aes"` + /// * `"pclmulqdq"` + /// * `"rdrand"` + /// * `"rdseed"` + /// * `"tsc"` + /// * `"mmx"` + /// * `"sse"` + /// * `"sse2"` + /// * `"sse3"` + /// * `"ssse3"` + /// * `"sse4.1"` + /// * `"sse4.2"` + /// * `"sse4a"` + /// * `"sha"` + /// * `"avx"` + /// * `"avx2"` + /// * `"avx512f"` + /// * `"avx512cd"` + /// * `"avx512er"` + /// * `"avx512pf"` + /// * `"avx512bw"` + /// * `"avx512dq"` + /// * `"avx512vl"` + /// * `"avx512ifma"` + /// * `"avx512vbmi"` + /// * `"avx512vpopcntdq"` + /// * `"fma"` + /// * `"bmi1"` + /// * `"bmi2"` + /// * `"abm"` + /// * `"lzcnt"` + /// * `"tbm"` + /// * `"popcnt"` + /// * `"fxsr"` + /// * `"xsave"` + /// * `"xsaveopt"` + /// * `"xsaves"` + /// * `"xsavec"` + /// + /// [docs]: https://software.intel.com/sites/landingpage/IntrinsicsGuide + #[stable(feature = "simd_x86", since = "1.27.0")] + @BIND_FEATURE_NAME: "abm"; "lzcnt"; // abm is a synonym for lzcnt + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] aes: "aes"; /// AES (Advanced Encryption Standard New Instructions AES-NI) - aes, + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] pclmulqdq: "pclmulqdq"; /// CLMUL (Carry-less Multiplication) - pclmulqdq, + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] rdrand: "rdrand"; /// RDRAND - rdrand, + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] rdseed: "rdseed"; /// RDSEED - rdseed, + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] tsc: "tsc"; /// TSC (Time Stamp Counter) - tsc, - /// MMX - mmx, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] mmx: "mmx"; + /// MMX (MultiMedia eXtensions) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] sse: "sse"; /// SSE (Streaming SIMD Extensions) - sse, + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] sse2: "sse2"; /// SSE2 (Streaming SIMD Extensions 2) - sse2, + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] sse3: "sse3"; /// SSE3 (Streaming SIMD Extensions 3) - sse3, + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] ssse3: "ssse3"; /// SSSE3 (Supplemental Streaming SIMD Extensions 3) - ssse3, + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] sse4_1: "sse4.1"; /// SSE4.1 (Streaming SIMD Extensions 4.1) - sse4_1, + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] sse4_2: "sse4.2"; /// SSE4.2 (Streaming SIMD Extensions 4.2) - sse4_2, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] sse4a: "sse4a"; /// SSE4a (Streaming SIMD Extensions 4a) - sse4a, + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] sha: "sha"; /// SHA - sha, + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx: "avx"; /// AVX (Advanced Vector Extensions) - avx, + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] avx2: "avx2"; /// AVX2 (Advanced Vector Extensions 2) - avx2, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] avx512f: "avx512f" ; /// AVX-512 F (Foundation) - avx512f, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] avx512cd: "avx512cd" ; /// AVX-512 CD (Conflict Detection Instructions) - avx512cd, - /// AVX-512 ER (Exponential and Reciprocal Instructions) - avx512er, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] avx512er: "avx512er"; + /// AVX-512 ER (Expo nential and Reciprocal Instructions) + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] avx512pf: "avx512pf"; /// AVX-512 PF (Prefetch Instructions) - avx512pf, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] avx512bw: "avx512bw"; /// AVX-512 BW (Byte and Word Instructions) - avx512bw, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] avx512dq: "avx512dq"; /// AVX-512 DQ (Doubleword and Quadword) - avx512dq, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] avx512vl: "avx512vl"; /// AVX-512 VL (Vector Length Extensions) - avx512vl, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] avx512ifma: "avx512ifma"; /// AVX-512 IFMA (Integer Fused Multiply Add) - avx512_ifma, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] avx512vbmi: "avx512vbmi"; /// AVX-512 VBMI (Vector Byte Manipulation Instructions) - avx512_vbmi, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] avx512vpopcntdq: "avx512vpopcntdq"; /// AVX-512 VPOPCNTDQ (Vector Population Count Doubleword and /// Quadword) - avx512_vpopcntdq, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] f16c: "f16c"; /// F16C (Conversions between IEEE-754 `binary16` and `binary32` formats) - f16c, + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] fma: "fma"; /// FMA (Fused Multiply Add) - fma, + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] bmi1: "bmi1" ; /// BMI1 (Bit Manipulation Instructions 1) - bmi, - /// BMI1 (Bit Manipulation Instructions 2) - bmi2, - /// ABM (Advanced Bit Manipulation) on AMD / LZCNT (Leading Zero - /// Count) on Intel - abm, + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] bmi2: "bmi2" ; + /// BMI2 (Bit Manipulation Instructions 2) + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] lzcnt: "lzcnt"; + /// ABM (Advanced Bit Manipulation) / LZCNT (Leading Zero Count) + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] tbm: "tbm"; /// TBM (Trailing Bit Manipulation) - tbm, + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] popcnt: "popcnt"; /// POPCNT (Population Count) - popcnt, + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] fxsr: "fxsr"; /// FXSR (Floating-point context fast save and restor) - fxsr, + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] xsave: "xsave"; /// XSAVE (Save Processor Extended States) - xsave, + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] xsaveopt: "xsaveopt"; /// XSAVEOPT (Save Processor Extended States Optimized) - xsaveopt, + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] xsaves: "xsaves"; /// XSAVES (Save Processor Extended States Supervisor) - xsaves, + @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] xsavec: "xsavec"; /// XSAVEC (Save Processor Extended States Compacted) - xsavec, - /// CMPXCH16B, a 16-byte compare-and-swap instruction - cmpxchg16b, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] cmpxchg16b: "cmpxchg16b"; + /// CMPXCH16B (16-byte compare-and-swap instruction) + @FEATURE: #[stable(feature = "simd_x86_adx", since = "1.33.0")] adx: "adx"; /// ADX, Intel ADX (Multi-Precision Add-Carry Instruction Extensions) - adx, + @FEATURE: #[unstable(feature = "stdsimd", issue = "27731")] rtm: "rtm"; /// RTM, Intel (Restricted Transactional Memory) - rtm, } diff --git a/crates/std_detect/src/detect/macros.rs b/crates/std_detect/src/detect/macros.rs new file mode 100644 index 0000000000..7285f59548 --- /dev/null +++ b/crates/std_detect/src/detect/macros.rs @@ -0,0 +1,95 @@ +#[allow(unused)] +macro_rules! features { + ( + @TARGET: $target:ident; + @MACRO_NAME: $macro_name:ident; + @MACRO_ATTRS: $(#[$macro_attrs:meta])* + $(@BIND_FEATURE_NAME: $bind_feature:tt; $feature_impl:tt; )* + $(@NO_RUNTIME_DETECTION: $nort_feature:tt; )* + $(@FEATURE: #[$stability_attr:meta] $feature:ident: $feature_lit:tt; $(#[$feature_comment:meta])*)* + ) => { + #[macro_export] + $(#[$macro_attrs])* + #[allow_internal_unstable(stdsimd_internal,stdsimd,staged_api)] + macro_rules! $macro_name { + $( + ($feature_lit) => { + $crate::detect::__is_feature_detected::$feature() + }; + )* + $( + ($bind_feature) => { $macro_name!($feature_impl); }; + )* + $( + ($nort_feature) => { + compile_error!( + concat!( + stringify!(nort_feature), + " feature cannot be detected at run-time" + ) + ) + }; + )* + ($t:tt,) => { + $macro_name!($t); + }; + ($t:tt) => { + compile_error!( + concat!( + concat!("unknown ", stringify!($target)), + concat!(" target feature: ", $t) + ) + ) + }; + } + + /// 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)] + #[derive(Copy, Clone)] + #[repr(u8)] + #[unstable(feature = "stdsimd_internal", issue = "0")] + pub enum Feature { + $( + $(#[$feature_comment])* + $feature, + )* + + // Do not add variants after last: + _last + } + + impl Feature { + pub fn to_str(self) -> &'static str { + match self { + $(Feature::$feature => $feature_lit,)* + Feature::_last => unreachable!(), + } + } + } + + /// Each function performs run-time feature detection for a single + /// feature. This allow us to use stability attributes on a per feature + /// basis. + /// + /// PLEASE: do not use this, it is an implementation detail subject + /// to change. + #[doc(hidden)] + pub mod __is_feature_detected { + $( + + /// PLEASE: do not use this, it is an implementation detail + /// subject to change. + #[doc(hidden)] + #[$stability_attr] + pub fn $feature() -> bool { + cfg!(target_feature = $feature_lit) || + $crate::detect::check_for($crate::detect::Feature::$feature) + } + )* + } + }; +} diff --git a/crates/std_detect/src/detect/mod.rs b/crates/std_detect/src/detect/mod.rs index 3e00c20554..6389a3fd75 100644 --- a/crates/std_detect/src/detect/mod.rs +++ b/crates/std_detect/src/detect/mod.rs @@ -20,6 +20,9 @@ #[macro_use] mod error_macros; +#[macro_use] +mod macros; + cfg_if! { if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { #[path = "arch/x86.rs"] @@ -52,13 +55,16 @@ cfg_if! { } else { // Unimplemented architecture: mod arch { + #[doc(hidden)] pub enum Feature { Null } + #[doc(hidden)] + pub mod __is_feature_detected {} } } } -pub use self::arch::Feature; +pub use self::arch::{Feature, __is_feature_detected}; mod bit; mod cache; @@ -96,3 +102,36 @@ cfg_if! { pub fn check_for(x: Feature) -> bool { cache::test(x as u32, self::os::detect_features) } + +/// Returns an `Iterator` where +/// `Item.0` is the feature name, and `Item.1` is a `bool` which +/// is `true` if the feature is supported by the host and `false` otherwise. +#[unstable(feature = "stdsimd", issue = "27731")] +pub fn features() -> impl Iterator { + cfg_if! { + if #[cfg(any( + target_arch = "x86", + target_arch = "x86_64", + target_arch = "arm", + target_arch = "aarch64", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "mips", + target_arch = "mips64", + ))] { + fn impl_() -> impl Iterator { + (0_u8..Feature::_last as u8).map(|discriminant: u8| { + let f: Feature = unsafe { crate::mem::transmute(discriminant) }; + let name: &'static str = f.to_str(); + let enabled: bool = check_for(f); + (name, enabled) + }) + } + } else { + fn impl_() -> impl Iterator { + (0_u8..0_u8).map(|_x: u8| ("", false)) + } + } + } + impl_() +} diff --git a/crates/std_detect/src/detect/os/aarch64.rs b/crates/std_detect/src/detect/os/aarch64.rs index dfb8c87707..9adc938a26 100644 --- a/crates/std_detect/src/detect/os/aarch64.rs +++ b/crates/std_detect/src/detect/os/aarch64.rs @@ -16,7 +16,7 @@ //! - [Zircon implementation](https://fuchsia.googlesource.com/zircon/+/master/kernel/arch/arm64/feature.cpp) //! - [Linux documentation](https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt) -use crate::detect::{Feature, cache}; +use crate::detect::{cache, Feature}; /// Try to read the features from the system registers. /// @@ -33,7 +33,9 @@ pub(crate) fn detect_features() -> cache::Initializer { // ID_AA64ISAR0_EL1 - Instruction Set Attribute Register 0 let aa64isar0: u64; - unsafe { asm!("mrs $0, ID_AA64ISAR0_EL1" : "=r"(aa64isar0)); } + unsafe { + asm!("mrs $0, ID_AA64ISAR0_EL1" : "=r"(aa64isar0)); + } let aes = bits_shift(aa64isar0, 7, 4) >= 1; let pmull = bits_shift(aa64isar0, 7, 4) >= 2; @@ -47,7 +49,9 @@ pub(crate) fn detect_features() -> cache::Initializer { // ID_AA64PFR0_EL1 - Processor Feature Register 0 let aa64pfr0: u64; - unsafe { asm!("mrs $0, ID_AA64PFR0_EL1" : "=r"(aa64pfr0)); } + unsafe { + asm!("mrs $0, ID_AA64PFR0_EL1" : "=r"(aa64pfr0)); + } let fp = bits_shift(aa64pfr0, 19, 16) < 0xF; let fphp = bits_shift(aa64pfr0, 19, 16) >= 1; @@ -60,12 +64,17 @@ pub(crate) fn detect_features() -> cache::Initializer { enable_feature(Feature::asimd, fp && asimd && (!fphp | asimdhp)); // SIMD extensions require SIMD support: enable_feature(Feature::rdm, asimd && bits_shift(aa64isar0, 31, 28) >= 1); - enable_feature(Feature::dotprod, asimd && bits_shift(aa64isar0, 47, 44) >= 1); + enable_feature( + Feature::dotprod, + asimd && bits_shift(aa64isar0, 47, 44) >= 1, + ); enable_feature(Feature::sve, asimd && bits_shift(aa64pfr0, 35, 32) >= 1); // ID_AA64ISAR1_EL1 - Instruction Set Attribute Register 1 let aa64isar1: u64; - unsafe { asm!("mrs $0, ID_AA64ISAR1_EL1" : "=r"(aa64isar1)); } + unsafe { + asm!("mrs $0, ID_AA64ISAR1_EL1" : "=r"(aa64isar1)); + } enable_feature(Feature::rcpc, bits_shift(aa64isar1, 23, 20) >= 1); } diff --git a/crates/std_detect/src/detect/os/freebsd/arm.rs b/crates/std_detect/src/detect/os/freebsd/arm.rs index 38e37721ef..4c9d763b44 100644 --- a/crates/std_detect/src/detect/os/freebsd/arm.rs +++ b/crates/std_detect/src/detect/os/freebsd/arm.rs @@ -1,7 +1,7 @@ //! Run-time feature detection for ARM on FreeBSD -use crate::detect::{Feature, cache}; -use super::{auxvec}; +use super::auxvec; +use crate::detect::{cache, Feature}; /// Try to read the features from the auxiliary vector pub(crate) fn detect_features() -> cache::Initializer { diff --git a/crates/std_detect/src/detect/os/freebsd/auxvec.rs b/crates/std_detect/src/detect/os/freebsd/auxvec.rs index a2bac76760..c595ec459b 100644 --- a/crates/std_detect/src/detect/os/freebsd/auxvec.rs +++ b/crates/std_detect/src/detect/os/freebsd/auxvec.rs @@ -44,13 +44,13 @@ pub(crate) fn auxv() -> Result { fn archauxv(key: usize) -> Result { use crate::mem; - #[derive (Copy, Clone)] + #[derive(Copy, Clone)] #[repr(C)] pub struct Elf_Auxinfo { pub a_type: usize, pub a_un: unnamed, } - #[derive (Copy, Clone)] + #[derive(Copy, Clone)] #[repr(C)] pub union unnamed { pub a_val: libc::c_long, @@ -58,22 +58,30 @@ fn archauxv(key: usize) -> Result { pub a_fcn: Option ()>, } - let mut auxv: [Elf_Auxinfo; 27] = - [Elf_Auxinfo{a_type: 0, a_un: unnamed{a_val: 0,},}; 27]; + let mut auxv: [Elf_Auxinfo; 27] = [Elf_Auxinfo { + a_type: 0, + a_un: unnamed { a_val: 0 }, + }; 27]; let mut len: libc::c_uint = mem::size_of_val(&auxv) as libc::c_uint; unsafe { - let mut mib = [libc::CTL_KERN, libc::KERN_PROC, libc::KERN_PROC_AUXV, libc::getpid()]; - - let ret = libc::sysctl(mib.as_mut_ptr(), - mib.len() as u32, - &mut auxv as *mut _ as *mut _, - &mut len as *mut _ as *mut _, - 0 as *mut libc::c_void, - 0, - ); - + let mut mib = [ + libc::CTL_KERN, + libc::KERN_PROC, + libc::KERN_PROC_AUXV, + libc::getpid(), + ]; + + let ret = libc::sysctl( + mib.as_mut_ptr(), + mib.len() as u32, + &mut auxv as *mut _ as *mut _, + &mut len as *mut _ as *mut _, + 0 as *mut libc::c_void, + 0, + ); + if ret != -1 { for i in 0..auxv.len() { if auxv[i].a_type == key { diff --git a/crates/std_detect/src/detect/os/freebsd/powerpc.rs b/crates/std_detect/src/detect/os/freebsd/powerpc.rs index 52a71e672a..6bfab631a9 100644 --- a/crates/std_detect/src/detect/os/freebsd/powerpc.rs +++ b/crates/std_detect/src/detect/os/freebsd/powerpc.rs @@ -1,7 +1,7 @@ //! Run-time feature detection for PowerPC on FreeBSD. -use crate::detect::{Feature, cache}; -use super::{auxvec}; +use super::auxvec; +use crate::detect::{cache, Feature}; pub(crate) fn detect_features() -> cache::Initializer { let mut value = cache::Initializer::default(); diff --git a/crates/std_detect/src/detect/os/linux/aarch64.rs b/crates/std_detect/src/detect/os/linux/aarch64.rs index 43c0976daf..b1b68f763e 100644 --- a/crates/std_detect/src/detect/os/linux/aarch64.rs +++ b/crates/std_detect/src/detect/os/linux/aarch64.rs @@ -1,7 +1,7 @@ //! Run-time feature detection for Aarch64 on Linux. -use crate::detect::{Feature, cache, bit}; use super::{auxvec, cpuinfo}; +use crate::detect::{bit, cache, Feature}; /// Try to read the features from the auxiliary vector, and if that fails, try /// to read them from /proc/cpuinfo. @@ -21,16 +21,16 @@ pub(crate) fn detect_features() -> cache::Initializer { /// /// [hwcap]: https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/hwcap.h struct AtHwcap { - fp: bool, // 0 + fp: bool, // 0 asimd: bool, // 1 // evtstrm: bool, // 2 - aes: bool, // 3 - pmull: bool, // 4 - sha1: bool, // 5 - sha2: bool, // 6 - crc32: bool, // 7 + aes: bool, // 3 + pmull: bool, // 4 + sha1: bool, // 5 + sha2: bool, // 6 + crc32: bool, // 7 atomics: bool, // 8 - fphp: bool, // 9 + fphp: bool, // 9 asimdhp: bool, // 10 // cpuid: bool, // 11 asimdrdm: bool, // 12 @@ -144,7 +144,10 @@ impl AtHwcap { enable_feature(Feature::sve, self.sve && asimd); // Crypto is specified as AES + PMULL + SHA1 + SHA2 per LLVM/hosts.cpp - enable_feature(Feature::crypto, self.aes && self.pmull && self.sha1 && self.sha2); + enable_feature( + Feature::crypto, + self.aes && self.pmull && self.sha1 && self.sha2, + ); } value } diff --git a/crates/std_detect/src/detect/os/linux/arm.rs b/crates/std_detect/src/detect/os/linux/arm.rs index 95624e1285..a1b28dad70 100644 --- a/crates/std_detect/src/detect/os/linux/arm.rs +++ b/crates/std_detect/src/detect/os/linux/arm.rs @@ -1,7 +1,7 @@ //! Run-time feature detection for ARM on Linux. -use crate::detect::{Feature, cache, bit}; use super::{auxvec, cpuinfo}; +use crate::detect::{bit, cache, Feature}; /// Try to read the features from the auxiliary vector, and if that fails, try /// to read them from /proc/cpuinfo. @@ -23,8 +23,11 @@ pub(crate) fn detect_features() -> cache::Initializer { } if let Ok(c) = cpuinfo::CpuInfo::new() { - enable_feature(&mut value, Feature::neon, c.field("Features").has("neon") && - !has_broken_neon(&c)); + enable_feature( + &mut value, + Feature::neon, + c.field("Features").has("neon") && !has_broken_neon(&c), + ); enable_feature(&mut value, Feature::pmull, c.field("Features").has("pmull")); return value; } diff --git a/crates/std_detect/src/detect/os/linux/auxvec.rs b/crates/std_detect/src/detect/os/linux/auxvec.rs index 07b6432eaf..6ebae67fbf 100644 --- a/crates/std_detect/src/detect/os/linux/auxvec.rs +++ b/crates/std_detect/src/detect/os/linux/auxvec.rs @@ -51,12 +51,12 @@ pub(crate) struct AuxVec { /// [auxvec_h]: https://github.com/torvalds/linux/blob/master/include/uapi/linux/auxvec.h /// [auxv_docs]: https://docs.rs/auxv/0.3.3/auxv/ pub(crate) fn auxv() -> Result { - #[cfg(feature = "std_detect_dlsym_getauxval")] { + #[cfg(feature = "std_detect_dlsym_getauxval")] + { // Try to call a dynamically-linked getauxval function. if let Ok(hwcap) = getauxval(AT_HWCAP) { // Targets with only AT_HWCAP: - #[cfg(any(target_arch = "aarch64", target_arch = "mips", - target_arch = "mips64"))] + #[cfg(any(target_arch = "aarch64", target_arch = "mips", target_arch = "mips64"))] { if hwcap != 0 { return Ok(AuxVec { hwcap }); @@ -74,22 +74,24 @@ pub(crate) fn auxv() -> Result { } drop(hwcap); } - #[cfg(feature = "std_detect_file_io")] { + #[cfg(feature = "std_detect_file_io")] + { // If calling getauxval fails, try to read the auxiliary vector from // its file: auxv_from_file("/proc/self/auxv") } - #[cfg(not(feature = "std_detect_file_io"))] { + #[cfg(not(feature = "std_detect_file_io"))] + { Err(()) } } - #[cfg(not(feature = "std_detect_dlsym_getauxval"))] { + #[cfg(not(feature = "std_detect_dlsym_getauxval"))] + { let hwcap = unsafe { ffi_getauxval(AT_HWCAP) }; // Targets with only AT_HWCAP: - #[cfg(any(target_arch = "aarch64", target_arch = "mips", - target_arch = "mips64"))] + #[cfg(any(target_arch = "aarch64", target_arch = "mips", target_arch = "mips64"))] { if hwcap != 0 { return Ok(AuxVec { hwcap }); @@ -115,10 +117,7 @@ fn getauxval(key: usize) -> Result { use libc; pub type F = unsafe extern "C" fn(usize) -> usize; unsafe { - let ptr = libc::dlsym( - libc::RTLD_DEFAULT, - "getauxval\0".as_ptr() as *const _, - ); + let ptr = libc::dlsym(libc::RTLD_DEFAULT, "getauxval\0".as_ptr() as *const _); if ptr.is_null() { return Err(()); } @@ -141,8 +140,7 @@ fn auxv_from_file(file: &str) -> Result { // 2*32 `usize` elements is enough to read the whole vector. let mut buf = [0_usize; 64]; { - let raw: &mut [u8; 64 * mem::size_of::()] = - unsafe { mem::transmute(&mut buf) }; + let raw: &mut [u8; 64 * mem::size_of::()] = unsafe { mem::transmute(&mut buf) }; file.read(raw).map_err(|_| ())?; } auxv_from_buf(&buf) @@ -153,8 +151,7 @@ fn auxv_from_file(file: &str) -> Result { #[cfg(feature = "std_detect_file_io")] fn auxv_from_buf(buf: &[usize; 64]) -> Result { // Targets with only AT_HWCAP: - #[cfg(any(target_arch = "aarch64", target_arch = "mips", - target_arch = "mips64"))] + #[cfg(any(target_arch = "aarch64", target_arch = "mips", target_arch = "mips64"))] { for el in buf.chunks(2) { match el[0] { @@ -193,8 +190,8 @@ mod tests { // using the auxv crate. #[cfg(feature = "std_detect_file_io")] fn auxv_crate_getprocfs(key: usize) -> Option { - use self::auxv_crate::AuxvType; use self::auxv_crate::procfs::search_procfs_auxv; + use self::auxv_crate::AuxvType; let k = key as AuxvType; match search_procfs_auxv(&[k]) { Ok(v) => Some(v[&k] as usize), @@ -206,8 +203,8 @@ mod tests { // using the auxv crate. #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] fn auxv_crate_getauxval(key: usize) -> Option { - use self::auxv_crate::AuxvType; use self::auxv_crate::getauxval::Getauxval; + use self::auxv_crate::AuxvType; let q = auxv_crate::getauxval::NativeGetauxval {}; match q.getauxval(key as AuxvType) { Ok(v) => Some(v as usize), diff --git a/crates/std_detect/src/detect/os/linux/cpuinfo.rs b/crates/std_detect/src/detect/os/linux/cpuinfo.rs index b316857853..f76c48a4b1 100644 --- a/crates/std_detect/src/detect/os/linux/cpuinfo.rs +++ b/crates/std_detect/src/detect/os/linux/cpuinfo.rs @@ -2,7 +2,7 @@ #![cfg_attr(not(target_arch = "arm"), allow(dead_code))] extern crate std; -use self::std::{prelude::v1::*, fs::File, io, io::Read}; +use self::std::{fs::File, io, io::Read, prelude::v1::*}; /// cpuinfo pub(crate) struct CpuInfo { @@ -150,8 +150,7 @@ power management: assert!(!cpuinfo.field("flags").has("avx")); } - const ARM_CORTEX_A53: &str = - r"Processor : AArch64 Processor rev 3 (aarch64) + const ARM_CORTEX_A53: &str = r"Processor : AArch64 Processor rev 3 (aarch64) processor : 0 processor : 1 processor : 2 diff --git a/crates/std_detect/src/detect/os/linux/mips.rs b/crates/std_detect/src/detect/os/linux/mips.rs index 6486673f80..9c030f41a0 100644 --- a/crates/std_detect/src/detect/os/linux/mips.rs +++ b/crates/std_detect/src/detect/os/linux/mips.rs @@ -1,7 +1,7 @@ //! Run-time feature detection for MIPS on Linux. -use crate::detect::{Feature, cache, bit}; use super::auxvec; +use crate::detect::{bit, cache, Feature}; /// Try to read the features from the auxiliary vector, and if that fails, try /// to read them from `/proc/cpuinfo`. diff --git a/crates/std_detect/src/detect/os/linux/powerpc.rs b/crates/std_detect/src/detect/os/linux/powerpc.rs index 5be35b96dd..97afe49fe5 100644 --- a/crates/std_detect/src/detect/os/linux/powerpc.rs +++ b/crates/std_detect/src/detect/os/linux/powerpc.rs @@ -1,7 +1,7 @@ //! Run-time feature detection for PowerPC on Linux. -use crate::detect::{Feature, cache}; use super::{auxvec, cpuinfo}; +use crate::detect::{cache, Feature}; /// Try to read the features from the auxiliary vector, and if that fails, try /// to read them from /proc/cpuinfo. diff --git a/crates/std_detect/src/detect/os/x86.rs b/crates/std_detect/src/detect/os/x86.rs index d9d286071a..c653771c43 100644 --- a/crates/std_detect/src/detect/os/x86.rs +++ b/crates/std_detect/src/detect/os/x86.rs @@ -7,7 +7,7 @@ use crate::arch::x86_64::*; use crate::mem; -use crate::detect::{Feature, cache, bit}; +use crate::detect::{bit, cache, Feature}; /// Run-time feature detection on x86 works by using the CPUID instruction. /// @@ -73,8 +73,7 @@ pub(crate) fn detect_features() -> cache::Initializer { // EAX = 7, ECX = 0: Queries "Extended Features"; // Contains information about bmi,bmi2, and avx2 support. - let (extended_features_ebx, extended_features_ecx) = if max_basic_leaf >= 7 - { + let (extended_features_ebx, extended_features_ecx) = if max_basic_leaf >= 7 { let CpuidResult { ebx, ecx, .. } = unsafe { __cpuid(0x0000_0007_u32) }; (ebx, ecx) } else { @@ -126,7 +125,7 @@ pub(crate) fn detect_features() -> cache::Initializer { enable(proc_info_edx, 26, Feature::sse2); enable(extended_features_ebx, 29, Feature::sha); - enable(extended_features_ebx, 3, Feature::bmi); + enable(extended_features_ebx, 3, Feature::bmi1); enable(extended_features_ebx, 8, Feature::bmi2); // `XSAVE` and `AVX` support: @@ -203,18 +202,14 @@ pub(crate) fn detect_features() -> cache::Initializer { if os_avx512_support { enable(extended_features_ebx, 16, Feature::avx512f); enable(extended_features_ebx, 17, Feature::avx512dq); - enable(extended_features_ebx, 21, Feature::avx512_ifma); + enable(extended_features_ebx, 21, Feature::avx512ifma); enable(extended_features_ebx, 26, Feature::avx512pf); enable(extended_features_ebx, 27, Feature::avx512er); enable(extended_features_ebx, 28, Feature::avx512cd); enable(extended_features_ebx, 30, Feature::avx512bw); enable(extended_features_ebx, 31, Feature::avx512vl); - enable(extended_features_ecx, 1, Feature::avx512_vbmi); - enable( - extended_features_ecx, - 14, - Feature::avx512_vpopcntdq, - ); + enable(extended_features_ecx, 1, Feature::avx512vbmi); + enable(extended_features_ecx, 14, Feature::avx512vpopcntdq); } } } @@ -227,7 +222,8 @@ pub(crate) fn detect_features() -> cache::Initializer { // // The `is_x86_feature_detected!("lzcnt")` macro then // internally maps to Feature::abm. - enable(extended_proc_info_ecx, 5, Feature::abm); + enable(extended_proc_info_ecx, 5, Feature::lzcnt); + // As Hygon Dhyana originates from AMD technology and shares most of the architecture with // AMD's family 17h, but with different CPU Vendor ID("HygonGenuine")/Family series // number(Family 18h). @@ -303,7 +299,10 @@ mod tests { 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!("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()); @@ -357,13 +356,7 @@ mod tests { 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(), - ); + assert_eq!(is_x86_feature_detected!("adx"), information.adx(),); + assert_eq!(is_x86_feature_detected!("rtm"), information.rtm(),); } } diff --git a/crates/std_detect/tests/cpu-detection.rs b/crates/std_detect/tests/cpu-detection.rs index d0c9901c4c..d441f4e1ef 100644 --- a/crates/std_detect/tests/cpu-detection.rs +++ b/crates/std_detect/tests/cpu-detection.rs @@ -1,7 +1,6 @@ #![feature(stdsimd)] #![allow(clippy::option_unwrap_used, clippy::use_debug, clippy::print_stdout)] - -#[cfg(any( +#![cfg(any( target_arch = "arm", target_arch = "aarch64", target_arch = "x86", @@ -9,9 +8,17 @@ target_arch = "powerpc", target_arch = "powerpc64" ))] + #[macro_use] extern crate std_detect; +#[test] +fn all() { + for (f, e) in std_detect::detect::features() { + println!("{}: {}", f, e); + } +} + #[test] #[cfg(all(target_arch = "arm", any(target_os = "linux", target_os = "android")))] fn arm_linux() { @@ -73,17 +80,17 @@ fn x86_all() { 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!("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!("avx512ifma: {:?}", is_x86_feature_detected!("avx512ifma")); + println!("avx512vbmi: {:?}", is_x86_feature_detected!("avx512vbmi")); println!( - "avx512_vpopcntdq {:?}", + "avx512vpopcntdq: {:?}", is_x86_feature_detected!("avx512vpopcntdq") ); println!("f16c: {:?}", is_x86_feature_detected!("f16c")); diff --git a/crates/stdarch-test/src/disassembly.rs b/crates/stdarch-test/src/disassembly.rs index 0decd889d2..d82b07d0a8 100644 --- a/crates/stdarch-test/src/disassembly.rs +++ b/crates/stdarch-test/src/disassembly.rs @@ -1,7 +1,7 @@ //! Disassembly calling function for most targets. -use std::{env, collections::HashSet, process::Command, str}; use crate::Function; +use std::{collections::HashSet, env, process::Command, str}; // Extracts the "shim" name from the `symbol`. fn normalize(mut symbol: &str) -> String { @@ -38,63 +38,56 @@ fn normalize(mut symbol: &str) -> String { pub(crate) fn disassemble_myself() -> HashSet { let me = env::current_exe().expect("failed to get current exe"); - let disassembly = if cfg!(target_arch = "x86_64") - && cfg!(target_os = "windows") - && cfg!(target_env = "msvc") - { - let mut cmd = cc::windows_registry::find( - "x86_64-pc-windows-msvc", - "dumpbin.exe", - ).expect("failed to find `dumpbin` tool"); - let output = cmd - .arg("/DISASM") - .arg(&me) - .output() - .expect("failed to execute dumpbin"); - println!( - "{}\n{}", - output.status, - String::from_utf8_lossy(&output.stderr) - ); - assert!(output.status.success()); - // Windows does not return valid UTF-8 output: - String::from_utf8_lossy(Vec::leak(output.stdout)) - } else if cfg!(target_os = "windows") { - panic!("disassembly unimplemented") - } else if cfg!(target_os = "macos") { - let output = Command::new("otool") - .arg("-vt") - .arg(&me) - .output() - .expect("failed to execute otool"); - println!( - "{}\n{}", - output.status, - String::from_utf8_lossy(&output.stderr) - ); - assert!(output.status.success()); - - String::from_utf8_lossy(Vec::leak(output.stdout)) - } else { - let objdump = - env::var("OBJDUMP").unwrap_or_else(|_| "objdump".to_string()); - let output = Command::new(objdump.clone()) - .arg("--disassemble") - .arg(&me) - .output() - .unwrap_or_else(|_| panic!( - "failed to execute objdump. OBJDUMP={}", - objdump - )); - println!( - "{}\n{}", - output.status, - String::from_utf8_lossy(&output.stderr) - ); - assert!(output.status.success()); - - String::from_utf8_lossy(Vec::leak(output.stdout)) - }; + let disassembly = + if cfg!(target_arch = "x86_64") && cfg!(target_os = "windows") && cfg!(target_env = "msvc") + { + let mut cmd = cc::windows_registry::find("x86_64-pc-windows-msvc", "dumpbin.exe") + .expect("failed to find `dumpbin` tool"); + let output = cmd + .arg("/DISASM") + .arg(&me) + .output() + .expect("failed to execute dumpbin"); + println!( + "{}\n{}", + output.status, + String::from_utf8_lossy(&output.stderr) + ); + assert!(output.status.success()); + // Windows does not return valid UTF-8 output: + String::from_utf8_lossy(Vec::leak(output.stdout)) + } else if cfg!(target_os = "windows") { + panic!("disassembly unimplemented") + } else if cfg!(target_os = "macos") { + let output = Command::new("otool") + .arg("-vt") + .arg(&me) + .output() + .expect("failed to execute otool"); + println!( + "{}\n{}", + output.status, + String::from_utf8_lossy(&output.stderr) + ); + assert!(output.status.success()); + + String::from_utf8_lossy(Vec::leak(output.stdout)) + } else { + let objdump = env::var("OBJDUMP").unwrap_or_else(|_| "objdump".to_string()); + let output = Command::new(objdump.clone()) + .arg("--disassemble") + .arg(&me) + .output() + .unwrap_or_else(|_| panic!("failed to execute objdump. OBJDUMP={}", objdump)); + println!( + "{}\n{}", + output.status, + String::from_utf8_lossy(&output.stderr) + ); + assert!(output.status.success()); + + String::from_utf8_lossy(Vec::leak(output.stdout)) + }; parse(&disassembly) } @@ -102,7 +95,10 @@ pub(crate) fn disassemble_myself() -> HashSet { fn parse(output: &str) -> HashSet { let mut lines = output.lines(); - println!("First 100 lines of the disassembly input containing {} lines:", lines.clone().count()); + println!( + "First 100 lines of the disassembly input containing {} lines:", + lines.clone().count() + ); for line in output.lines().take(100) { println!("{}", line); } @@ -111,7 +107,7 @@ fn parse(output: &str) -> HashSet { let mut cached_header = None; while let Some(header) = cached_header.take().or_else(|| lines.next()) { if !header.ends_with(':') || !header.contains("stdarch_test_shim") { - continue + continue; } eprintln!("header: {}", header); let symbol = normalize(header); @@ -146,9 +142,8 @@ fn parse(output: &str) -> HashSet { instruction .split_whitespace() .skip(1) - .skip_while(|s| { - s.len() == 2 && usize::from_str_radix(s, 16).is_ok() - }).map(std::string::ToString::to_string) + .skip_while(|s| s.len() == 2 && usize::from_str_radix(s, 16).is_ok()) + .map(std::string::ToString::to_string) .skip_while(|s| *s == "lock") // skip x86-specific prefix .collect::>() } else { @@ -156,20 +151,16 @@ fn parse(output: &str) -> HashSet { // Each line of instructions should look like: // // $rel_offset: ab cd ef 00 $instruction... - let expected_len - = if cfg!(target_arch = "arm") || cfg!(target_arch = "aarch64") { - 8 - } else { - 2 - }; + let expected_len = if cfg!(target_arch = "arm") || cfg!(target_arch = "aarch64") { + 8 + } else { + 2 + }; instruction .split_whitespace() .skip(1) - .skip_while(|s| { - s.len() == expected_len - && usize::from_str_radix(s, 16).is_ok() - }) + .skip_while(|s| s.len() == expected_len && usize::from_str_radix(s, 16).is_ok()) .skip_while(|s| *s == "lock") // skip x86-specific prefix .map(std::string::ToString::to_string) .collect::>() @@ -178,7 +169,7 @@ fn parse(output: &str) -> HashSet { } let function = Function { name: symbol, - instrs: instructions + instrs: instructions, }; assert!(functions.insert(function)); } diff --git a/crates/stdarch-test/src/wasm.rs b/crates/stdarch-test/src/wasm.rs index b31051bc68..fc4ced6282 100644 --- a/crates/stdarch-test/src/wasm.rs +++ b/crates/stdarch-test/src/wasm.rs @@ -42,8 +42,7 @@ pub(crate) fn disassemble_myself() -> HashSet { args.push(&js_shim.display().to_string().into()); args.push(&"--enable-simd".into()); let opts = js_sys::Object::new(); - js_sys::Reflect::set(&opts, &"maxBuffer".into(), &(200 * 1024 * 1024).into()) - .unwrap(); + js_sys::Reflect::set(&opts, &"maxBuffer".into(), &(200 * 1024 * 1024).into()).unwrap(); let output = exec_file_sync("wasm2wat", &args, &opts).to_string(); let mut ret: HashSet = HashSet::new();