| //! This module implements minimal run-time feature detection for x86. |
| //! |
| //! The features are detected using the `detect_features` function below. |
| //! This function uses the CPUID instruction to read the feature flags from the |
| //! CPU and encodes them in an `usize` where each bit position represents |
| //! whether a feature is available (bit is set) or unavaiable (bit is cleared). |
| //! |
| //! The enum `Feature` is used to map bit positions to feature names, and the |
| //! the `__crate::detect::check_for!` macro is used to map string literals (e.g., |
| //! "avx") to these bit positions (e.g., `Feature::avx`). |
| //! |
| //! The run-time feature detection is performed by the |
| //! `__crate::detect::check_for(Feature) -> bool` function. On its first call, |
| //! 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. |
| |
| /// 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 { |
| /// AES (Advanced Encryption Standard New Instructions AES-NI) |
| aes, |
| /// CLMUL (Carry-less Multiplication) |
| pclmulqdq, |
| /// RDRAND |
| rdrand, |
| /// RDSEED |
| rdseed, |
| /// TSC (Time Stamp Counter) |
| tsc, |
| /// MMX |
| mmx, |
| /// SSE (Streaming SIMD Extensions) |
| sse, |
| /// SSE2 (Streaming SIMD Extensions 2) |
| sse2, |
| /// SSE3 (Streaming SIMD Extensions 3) |
| sse3, |
| /// SSSE3 (Supplemental Streaming SIMD Extensions 3) |
| ssse3, |
| /// SSE4.1 (Streaming SIMD Extensions 4.1) |
| sse4_1, |
| /// SSE4.2 (Streaming SIMD Extensions 4.2) |
| sse4_2, |
| /// SSE4a (Streaming SIMD Extensions 4a) |
| sse4a, |
| /// SHA |
| sha, |
| /// AVX (Advanced Vector Extensions) |
| avx, |
| /// AVX2 (Advanced Vector Extensions 2) |
| avx2, |
| /// AVX-512 F (Foundation) |
| avx512f, |
| /// AVX-512 CD (Conflict Detection Instructions) |
| avx512cd, |
| /// AVX-512 ER (Exponential and Reciprocal Instructions) |
| avx512er, |
| /// AVX-512 PF (Prefetch Instructions) |
| avx512pf, |
| /// AVX-512 BW (Byte and Word Instructions) |
| avx512bw, |
| /// AVX-512 DQ (Doubleword and Quadword) |
| avx512dq, |
| /// AVX-512 VL (Vector Length Extensions) |
| avx512vl, |
| /// AVX-512 IFMA (Integer Fused Multiply Add) |
| avx512_ifma, |
| /// AVX-512 VBMI (Vector Byte Manipulation Instructions) |
| avx512_vbmi, |
| /// AVX-512 VPOPCNTDQ (Vector Population Count Doubleword and |
| /// Quadword) |
| avx512_vpopcntdq, |
| /// F16C (Conversions between IEEE-754 `binary16` and `binary32` formats) |
| f16c, |
| /// FMA (Fused Multiply Add) |
| fma, |
| /// 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, |
| /// TBM (Trailing Bit Manipulation) |
| tbm, |
| /// POPCNT (Population Count) |
| popcnt, |
| /// FXSR (Floating-point context fast save and restor) |
| fxsr, |
| /// XSAVE (Save Processor Extended States) |
| xsave, |
| /// XSAVEOPT (Save Processor Extended States Optimized) |
| xsaveopt, |
| /// XSAVES (Save Processor Extended States Supervisor) |
| xsaves, |
| /// XSAVEC (Save Processor Extended States Compacted) |
| xsavec, |
| /// CMPXCH16B, a 16-byte compare-and-swap instruction |
| cmpxchg16b, |
| /// ADX, Intel ADX (Multi-Precision Add-Carry Instruction Extensions) |
| adx, |
| /// RTM, Intel (Restricted Transactional Memory) |
| rtm, |
| } |