#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SimdLevel {
Scalar,
Sse42,
Avx2,
Avx512,
Neon,
Sve,
}
impl SimdLevel {
pub fn name(&self) -> &'static str {
match self {
SimdLevel::Scalar => "Scalar",
SimdLevel::Sse42 => "SSE4.2",
SimdLevel::Avx2 => "AVX2",
SimdLevel::Avx512 => "AVX-512",
SimdLevel::Neon => "NEON",
SimdLevel::Sve => "SVE",
}
}
pub fn vector_width_bits(&self) -> usize {
match self {
SimdLevel::Scalar => 64,
SimdLevel::Sse42 => 128,
SimdLevel::Avx2 => 256,
SimdLevel::Avx512 => 512,
SimdLevel::Neon => 128,
SimdLevel::Sve => 128, }
}
pub fn f64_lanes(&self) -> usize {
self.vector_width_bits() / 64
}
pub fn i64_lanes(&self) -> usize {
self.vector_width_bits() / 64
}
}
#[derive(Debug, Clone)]
pub struct CpuFeatures {
pub has_sse42: bool,
pub has_avx2: bool,
pub has_avx512f: bool,
pub has_avx512dq: bool,
pub has_neon: bool,
pub has_sve: bool,
}
impl CpuFeatures {
pub fn get() -> Self {
#[cfg(target_arch = "x86_64")]
{
Self {
has_sse42: std::arch::is_x86_feature_detected!("sse4.2"),
has_avx2: std::arch::is_x86_feature_detected!("avx2"),
has_avx512f: std::arch::is_x86_feature_detected!("avx512f"),
has_avx512dq: std::arch::is_x86_feature_detected!("avx512dq"),
has_neon: false,
has_sve: false,
}
}
#[cfg(target_arch = "aarch64")]
{
Self {
has_sse42: false,
has_avx2: false,
has_avx512f: false,
has_avx512dq: false,
has_neon: std::arch::is_aarch64_feature_detected!("neon"),
has_sve: std::arch::is_aarch64_feature_detected!("sve"),
}
}
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
{
Self {
has_sse42: false,
has_avx2: false,
has_avx512f: false,
has_avx512dq: false,
has_neon: false,
has_sve: false,
}
}
}
pub fn best_simd_level(&self) -> SimdLevel {
if self.has_avx512f && self.has_avx512dq {
SimdLevel::Avx512
} else if self.has_avx2 {
SimdLevel::Avx2
} else if self.has_sse42 {
SimdLevel::Sse42
} else if self.has_sve {
SimdLevel::Sve
} else if self.has_neon {
SimdLevel::Neon
} else {
SimdLevel::Scalar
}
}
}
pub mod dispatched {
use super::*;
pub fn add_f64(a: &[f64], b: &[f64]) -> Vec<f64> {
assert_eq!(a.len(), b.len());
a.iter().zip(b.iter()).map(|(x, y)| x + y).collect()
}
pub fn mul_f64(a: &[f64], b: &[f64]) -> Vec<f64> {
assert_eq!(a.len(), b.len());
a.iter().zip(b.iter()).map(|(x, y)| x * y).collect()
}
pub fn sum_f64(values: &[f64]) -> f64 {
crate::select::columnar::simd_ops::intrinsics::sum_f64(values)
}
pub fn active_level() -> SimdLevel {
CpuFeatures::get().best_simd_level()
}
}