axiolid_backend_cpu/
features.rs

1//! Runtime CPU feature detection for portable binaries.
2
3/// Instruction set selected for specialized kernels.
4#[non_exhaustive]
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
6pub enum CpuInstructionSet {
7    /// Architecture-portable scalar path.
8    Portable,
9    /// x86-64 SSE4.2 path.
10    Sse42,
11    /// x86-64 AVX2 + FMA path.
12    Avx2,
13    /// x86-64 AVX-512 foundation path.
14    Avx512,
15    /// AArch64 NEON path.
16    Neon,
17}
18
19/// Runtime-detected CPU capabilities. No compile-time `target-cpu=native` is
20/// required, so one binary remains safe on older machines.
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub struct CpuFeatures {
23    /// SSE4.2 available.
24    pub sse42: bool,
25    /// AVX2 and FMA available.
26    pub avx2_fma: bool,
27    /// AVX-512 foundation and DQ available.
28    pub avx512: bool,
29    /// AArch64 NEON available.
30    pub neon: bool,
31}
32
33impl CpuFeatures {
34    /// Detect features on the current process host.
35    pub fn detect() -> Self {
36        let mut features = Self {
37            sse42: false,
38            avx2_fma: false,
39            avx512: false,
40            neon: false,
41        };
42        #[cfg(target_arch = "x86_64")]
43        {
44            features.sse42 = std::is_x86_feature_detected!("sse4.2");
45            features.avx2_fma =
46                std::is_x86_feature_detected!("avx2") && std::is_x86_feature_detected!("fma");
47            features.avx512 = std::is_x86_feature_detected!("avx512f")
48                && std::is_x86_feature_detected!("avx512dq");
49        }
50        #[cfg(target_arch = "aarch64")]
51        {
52            features.neon = std::arch::is_aarch64_feature_detected!("neon");
53        }
54        features
55    }
56
57    /// Whether one implementation is safe to execute.
58    pub const fn supports(self, instruction_set: CpuInstructionSet) -> bool {
59        match instruction_set {
60            CpuInstructionSet::Portable => true,
61            CpuInstructionSet::Sse42 => self.sse42,
62            CpuInstructionSet::Avx2 => self.avx2_fma,
63            CpuInstructionSet::Avx512 => self.avx512,
64            CpuInstructionSet::Neon => self.neon,
65        }
66    }
67
68    /// Best compiled-compatible specialization, or portable scalar.
69    pub const fn best(self) -> CpuInstructionSet {
70        if self.avx512 {
71            CpuInstructionSet::Avx512
72        } else if self.avx2_fma {
73            CpuInstructionSet::Avx2
74        } else if self.sse42 {
75            CpuInstructionSet::Sse42
76        } else if self.neon {
77            CpuInstructionSet::Neon
78        } else {
79            CpuInstructionSet::Portable
80        }
81    }
82}