#![allow(non_snake_case)] use crate::mem::U32; #[repr(C)] #[derive(Debug, Copy, Clone, Default)] pub struct ZstdCpuid { pub f1c: U32, pub f1d: U32, pub f7b: U32, pub f7c: U32, } #[inline] pub fn ZSTD_cpuid() -> ZstdCpuid { #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { cpuid_x86() } #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] { ZstdCpuid::default() } } #[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}; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn cpuid_x86() -> ZstdCpuid { let mut out = ZstdCpuid::default(); let max: CpuidResult = __cpuid(0); if max.eax >= 1 { let r = __cpuid(1); out.f1c = r.ecx; out.f1d = r.edx; } if max.eax >= 7 { let r = __cpuid_count(7, 0); out.f7b = r.ebx; out.f7c = r.ecx; } out } macro_rules! cpuid_bit { ($fn_name:ident, $field:ident, $bit:expr) => { #[inline] pub fn $fn_name(cpuid: ZstdCpuid) -> bool { (cpuid.$field & (1u32 << $bit)) != 0 } }; } cpuid_bit!(ZSTD_cpuid_sse3, f1c, 0); cpuid_bit!(ZSTD_cpuid_pclmuldq, f1c, 1); cpuid_bit!(ZSTD_cpuid_dtes64, f1c, 2); cpuid_bit!(ZSTD_cpuid_monitor, f1c, 3); cpuid_bit!(ZSTD_cpuid_dscpl, f1c, 4); cpuid_bit!(ZSTD_cpuid_vmx, f1c, 5); cpuid_bit!(ZSTD_cpuid_smx, f1c, 6); cpuid_bit!(ZSTD_cpuid_eist, f1c, 7); cpuid_bit!(ZSTD_cpuid_tm2, f1c, 8); cpuid_bit!(ZSTD_cpuid_ssse3, f1c, 9); cpuid_bit!(ZSTD_cpuid_cnxtid, f1c, 10); cpuid_bit!(ZSTD_cpuid_fma, f1c, 12); cpuid_bit!(ZSTD_cpuid_cx16, f1c, 13); cpuid_bit!(ZSTD_cpuid_xtpr, f1c, 14); cpuid_bit!(ZSTD_cpuid_pdcm, f1c, 15); cpuid_bit!(ZSTD_cpuid_pcid, f1c, 17); cpuid_bit!(ZSTD_cpuid_dca, f1c, 18); cpuid_bit!(ZSTD_cpuid_sse41, f1c, 19); cpuid_bit!(ZSTD_cpuid_sse42, f1c, 20); cpuid_bit!(ZSTD_cpuid_x2apic, f1c, 21); cpuid_bit!(ZSTD_cpuid_movbe, f1c, 22); cpuid_bit!(ZSTD_cpuid_popcnt, f1c, 23); cpuid_bit!(ZSTD_cpuid_tscdeadline, f1c, 24); cpuid_bit!(ZSTD_cpuid_aes, f1c, 25); cpuid_bit!(ZSTD_cpuid_xsave, f1c, 26); cpuid_bit!(ZSTD_cpuid_osxsave, f1c, 27); cpuid_bit!(ZSTD_cpuid_avx, f1c, 28); cpuid_bit!(ZSTD_cpuid_f16c, f1c, 29); cpuid_bit!(ZSTD_cpuid_rdrand, f1c, 30); cpuid_bit!(ZSTD_cpuid_fpu, f1d, 0); cpuid_bit!(ZSTD_cpuid_vme, f1d, 1); cpuid_bit!(ZSTD_cpuid_de, f1d, 2); cpuid_bit!(ZSTD_cpuid_pse, f1d, 3); cpuid_bit!(ZSTD_cpuid_tsc, f1d, 4); cpuid_bit!(ZSTD_cpuid_msr, f1d, 5); cpuid_bit!(ZSTD_cpuid_pae, f1d, 6); cpuid_bit!(ZSTD_cpuid_mce, f1d, 7); cpuid_bit!(ZSTD_cpuid_cx8, f1d, 8); cpuid_bit!(ZSTD_cpuid_apic, f1d, 9); cpuid_bit!(ZSTD_cpuid_sep, f1d, 11); cpuid_bit!(ZSTD_cpuid_mtrr, f1d, 12); cpuid_bit!(ZSTD_cpuid_pge, f1d, 13); cpuid_bit!(ZSTD_cpuid_mca, f1d, 14); cpuid_bit!(ZSTD_cpuid_cmov, f1d, 15); cpuid_bit!(ZSTD_cpuid_pat, f1d, 16); cpuid_bit!(ZSTD_cpuid_pse36, f1d, 17); cpuid_bit!(ZSTD_cpuid_psn, f1d, 18); cpuid_bit!(ZSTD_cpuid_clfsh, f1d, 19); cpuid_bit!(ZSTD_cpuid_ds, f1d, 21); cpuid_bit!(ZSTD_cpuid_acpi, f1d, 22); cpuid_bit!(ZSTD_cpuid_mmx, f1d, 23); cpuid_bit!(ZSTD_cpuid_fxsr, f1d, 24); cpuid_bit!(ZSTD_cpuid_sse, f1d, 25); cpuid_bit!(ZSTD_cpuid_sse2, f1d, 26); cpuid_bit!(ZSTD_cpuid_ss, f1d, 27); cpuid_bit!(ZSTD_cpuid_htt, f1d, 28); cpuid_bit!(ZSTD_cpuid_tm, f1d, 29); cpuid_bit!(ZSTD_cpuid_pbe, f1d, 31); cpuid_bit!(ZSTD_cpuid_bmi1, f7b, 3); cpuid_bit!(ZSTD_cpuid_hle, f7b, 4); cpuid_bit!(ZSTD_cpuid_avx2, f7b, 5); cpuid_bit!(ZSTD_cpuid_smep, f7b, 7); cpuid_bit!(ZSTD_cpuid_bmi2, f7b, 8); cpuid_bit!(ZSTD_cpuid_erms, f7b, 9); cpuid_bit!(ZSTD_cpuid_invpcid, f7b, 10); cpuid_bit!(ZSTD_cpuid_rtm, f7b, 11); cpuid_bit!(ZSTD_cpuid_mpx, f7b, 14); cpuid_bit!(ZSTD_cpuid_avx512f, f7b, 16); cpuid_bit!(ZSTD_cpuid_avx512dq, f7b, 17); cpuid_bit!(ZSTD_cpuid_rdseed, f7b, 18); cpuid_bit!(ZSTD_cpuid_adx, f7b, 19); cpuid_bit!(ZSTD_cpuid_smap, f7b, 20); cpuid_bit!(ZSTD_cpuid_avx512ifma, f7b, 21); cpuid_bit!(ZSTD_cpuid_pcommit, f7b, 22); cpuid_bit!(ZSTD_cpuid_clflushopt, f7b, 23); cpuid_bit!(ZSTD_cpuid_clwb, f7b, 24); cpuid_bit!(ZSTD_cpuid_avx512pf, f7b, 26); cpuid_bit!(ZSTD_cpuid_avx512er, f7b, 27); cpuid_bit!(ZSTD_cpuid_avx512cd, f7b, 28); cpuid_bit!(ZSTD_cpuid_sha, f7b, 29); cpuid_bit!(ZSTD_cpuid_avx512bw, f7b, 30); cpuid_bit!(ZSTD_cpuid_avx512vl, f7b, 31); cpuid_bit!(ZSTD_cpuid_prefetchwt1, f7c, 0); cpuid_bit!(ZSTD_cpuid_avx512vbmi, f7c, 1); #[inline] pub fn ZSTD_cpuSupportsBmi2() -> bool { let cpuid = ZSTD_cpuid(); ZSTD_cpuid_bmi1(cpuid) && ZSTD_cpuid_bmi2(cpuid) } #[cfg(test)] mod tests { use super::*; #[test] fn feature_helpers_read_the_header_defined_bits() { let cpuid = ZstdCpuid { f1c: 1 << 20, f1d: 1 << 26, f7b: (1 << 3) | (1 << 8), f7c: 1 << 1, }; assert!(ZSTD_cpuid_sse42(cpuid)); assert!(ZSTD_cpuid_sse2(cpuid)); assert!(ZSTD_cpuid_bmi1(cpuid)); assert!(ZSTD_cpuid_bmi2(cpuid)); assert!(ZSTD_cpuid_avx512vbmi(cpuid)); assert!(!ZSTD_cpuid_avx2(cpuid)); } }