diff options
Diffstat (limited to 'third_party/rust/cpufeatures/src/x86.rs')
-rw-r--r-- | third_party/rust/cpufeatures/src/x86.rs | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/third_party/rust/cpufeatures/src/x86.rs b/third_party/rust/cpufeatures/src/x86.rs new file mode 100644 index 0000000000..c973b7446b --- /dev/null +++ b/third_party/rust/cpufeatures/src/x86.rs @@ -0,0 +1,105 @@ +//! x86/x86-64 CPU feature detection support. +//! +//! Portable, `no_std`-friendly implementation that relies on the x86 `CPUID` +//! instruction for feature detection. + +// Evaluate the given `$body` expression any of the supplied target features +// are not enabled. Otherwise returns true. +// +// The `$body` expression is not evaluated on SGX targets, and returns false +// on these targets unless *all* supplied target features are enabled. +#[macro_export] +#[doc(hidden)] +macro_rules! __unless_target_features { + ($($tf:tt),+ => $body:expr ) => {{ + #[cfg(not(all($(target_feature=$tf,)*)))] + { + #[cfg(not(target_env = "sgx"))] + $body + + // CPUID is not available on SGX targets + #[cfg(target_env = "sgx")] + false + } + + #[cfg(all($(target_feature=$tf,)*))] + true + }}; +} + +// Use CPUID to detect the presence of all supplied target features. +#[macro_export] +#[doc(hidden)] +macro_rules! __detect_target_features { + ($($tf:tt),+) => {{ + #[cfg(target_arch = "x86")] + use core::arch::x86::{__cpuid, __cpuid_count, CpuidResult}; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::{__cpuid, __cpuid_count, CpuidResult}; + + // These wrappers are workarounds around + // https://github.com/rust-lang/rust/issues/101346 + // + // DO NOT remove it until MSRV is bumped to a version + // with the issue fix (at least 1.64). + #[inline(never)] + unsafe fn cpuid(leaf: u32) -> CpuidResult { + __cpuid(leaf) + } + + #[inline(never)] + unsafe fn cpuid_count(leaf: u32, sub_leaf: u32) -> CpuidResult { + __cpuid_count(leaf, sub_leaf) + } + + let cr = unsafe { + [cpuid(1), cpuid_count(7, 0)] + }; + + $($crate::check!(cr, $tf) & )+ true + }}; +} + +macro_rules! __expand_check_macro { + ($(($name:tt $(, $i:expr, $reg:ident, $offset:expr)*)),* $(,)?) => { + #[macro_export] + #[doc(hidden)] + macro_rules! check { + $( + ($cr:expr, $name) => { + true + $( + & ($cr[$i].$reg & (1 << $offset) != 0) + )* + }; + )* + } + }; +} + +// Note that according to the [Intel manual][0] AVX2 and FMA require +// that we check availability of AVX before using them. +// +// [0]: https://www.intel.com/content/dam/develop/external/us/en/documents/36945 +__expand_check_macro! { + ("mmx", 0, edx, 23), + ("sse", 0, edx, 25), + ("sse2", 0, edx, 26), + ("sse3", 0, ecx, 0), + ("pclmulqdq", 0, ecx, 1), + ("ssse3", 0, ecx, 9), + ("fma", 0, ecx, 28, 0, ecx, 12), + ("sse4.1", 0, ecx, 19), + ("sse4.2", 0, ecx, 20), + ("popcnt", 0, ecx, 23), + ("aes", 0, ecx, 25), + ("avx", 0, ecx, 28), + ("rdrand", 0, ecx, 30), + ("sgx", 1, ebx, 2), + ("bmi1", 1, ebx, 3), + ("avx2", 0, ecx, 28, 1, ebx, 5), + ("bmi2", 1, ebx, 8), + ("rdseed", 1, ebx, 18), + ("adx", 1, ebx, 19), + ("sha", 1, ebx, 29), +} |