use std::sync::LazyLock;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SimdSupport {
None,
Neon,
Sse,
Avx2,
Avx512,
Avx512FP16,
Lsx,
Lasx,
}
pub static SIMD_SUPPORT: LazyLock<SimdSupport> = LazyLock::new(|| {
#[cfg(all(target_arch = "aarch64", any(target_os = "ios", target_os = "tvos")))]
{
SimdSupport::Neon
}
#[cfg(all(
target_arch = "aarch64",
not(any(target_os = "ios", target_os = "tvos"))
))]
{
if aarch64::has_neon_f16_support() {
SimdSupport::Neon
} else {
SimdSupport::None
}
}
#[cfg(target_arch = "x86_64")]
{
if x86::has_avx512() {
if x86::has_avx512_f16_support() {
SimdSupport::Avx512FP16
} else {
SimdSupport::Avx512
}
} else if is_x86_feature_detected!("avx2") {
SimdSupport::Avx2
} else {
SimdSupport::None
}
}
#[cfg(target_arch = "loongarch64")]
{
if loongarch64::has_lasx_support() {
SimdSupport::Lasx
} else if loongarch64::has_lsx_support() {
SimdSupport::Lsx
} else {
SimdSupport::None
}
}
});
#[cfg(target_arch = "x86_64")]
mod x86 {
use core::arch::x86_64::__cpuid;
#[inline]
fn check_flag(x: usize, position: u32) -> bool {
x & (1 << position) != 0
}
pub fn has_avx512_f16_support() -> bool {
if !has_avx512() {
return false;
}
#[allow(unused_unsafe)]
let ext_cpuid_result = unsafe { __cpuid(7) };
check_flag(ext_cpuid_result.edx as usize, 23)
}
pub fn has_avx512() -> bool {
is_x86_feature_detected!("avx512f")
}
}
#[cfg(all(target_arch = "aarch64", target_os = "macos"))]
mod aarch64 {
pub fn has_neon_f16_support() -> bool {
true
}
}
#[cfg(all(target_arch = "aarch64", target_os = "linux"))]
mod aarch64 {
pub fn has_neon_f16_support() -> bool {
let flags = unsafe { libc::getauxval(libc::AT_HWCAP) };
flags & libc::HWCAP_FPHP != 0
}
}
#[cfg(all(target_arch = "aarch64", target_os = "windows"))]
mod aarch64 {
pub fn has_neon_f16_support() -> bool {
false
}
}
#[cfg(target_arch = "loongarch64")]
mod loongarch64 {
pub fn has_lsx_support() -> bool {
let flags = unsafe { libc::getauxval(libc::AT_HWCAP) };
flags & libc::HWCAP_LOONGARCH_LSX != 0
}
pub fn has_lasx_support() -> bool {
let flags = unsafe { libc::getauxval(libc::AT_HWCAP) };
flags & libc::HWCAP_LOONGARCH_LASX != 0
}
}
#[cfg(all(target_arch = "aarch64", target_os = "android"))]
mod aarch64 {
pub fn has_neon_f16_support() -> bool {
false
}
}