#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum CpuInstructionSet {
Portable,
Sse42,
Avx2,
Avx512,
Neon,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CpuFeatures {
pub sse42: bool,
pub avx2_fma: bool,
pub avx512: bool,
pub neon: bool,
}
impl CpuFeatures {
pub fn detect() -> Self {
let mut features = Self {
sse42: false,
avx2_fma: false,
avx512: false,
neon: false,
};
#[cfg(target_arch = "x86_64")]
{
features.sse42 = std::is_x86_feature_detected!("sse4.2");
features.avx2_fma =
std::is_x86_feature_detected!("avx2") && std::is_x86_feature_detected!("fma");
features.avx512 = std::is_x86_feature_detected!("avx512f")
&& std::is_x86_feature_detected!("avx512dq");
}
#[cfg(target_arch = "aarch64")]
{
features.neon = std::arch::is_aarch64_feature_detected!("neon");
}
features
}
pub const fn supports(self, instruction_set: CpuInstructionSet) -> bool {
match instruction_set {
CpuInstructionSet::Portable => true,
CpuInstructionSet::Sse42 => self.sse42,
CpuInstructionSet::Avx2 => self.avx2_fma,
CpuInstructionSet::Avx512 => self.avx512,
CpuInstructionSet::Neon => self.neon,
}
}
pub const fn best(self) -> CpuInstructionSet {
if self.avx512 {
CpuInstructionSet::Avx512
} else if self.avx2_fma {
CpuInstructionSet::Avx2
} else if self.sse42 {
CpuInstructionSet::Sse42
} else if self.neon {
CpuInstructionSet::Neon
} else {
CpuInstructionSet::Portable
}
}
}