pub fn has_feature(name: &str) -> bool {
match crate::arch::detect_arch() {
crate::arch::Architecture::X86_64 => has_feature_x86(name),
crate::arch::Architecture::AArch64 => has_feature_arm(name),
_ => false,
}
}
fn has_feature_x86(name: &str) -> bool {
let (ecx1, edx1) = match crate::hardware_access::read_cpuid(1, 0) {
Some((_, _, c, d)) => (c, d),
None => return false,
};
match name {
"sse" => (edx1 & (1 << 25)) != 0,
"sse2" => (edx1 & (1 << 26)) != 0,
"sse3" => (ecx1 & (1 << 0)) != 0,
"ssse3" => (ecx1 & (1 << 9)) != 0,
"sse4_1" | "sse4.1" => (ecx1 & (1 << 19)) != 0,
"sse4_2" | "sse4.2" => (ecx1 & (1 << 20)) != 0,
"avx" => (ecx1 & (1 << 28)) != 0,
"aes" | "aes-ni" => (ecx1 & (1 << 25)) != 0,
"fma" | "fma3" => (ecx1 & (1 << 12)) != 0,
"pclmulqdq" => (ecx1 & (1 << 1)) != 0,
"popcnt" => (ecx1 & (1 << 23)) != 0,
"f16c" => (ecx1 & (1 << 29)) != 0,
"avx2" => crate::hardware_access::read_cpuid(7, 0)
.map(|(_, b, _, _)| (b & (1 << 5)) != 0)
.unwrap_or(false),
"bmi1" => crate::hardware_access::read_cpuid(7, 0)
.map(|(_, b, _, _)| (b & (1 << 3)) != 0)
.unwrap_or(false),
"bmi2" => crate::hardware_access::read_cpuid(7, 0)
.map(|(_, b, _, _)| (b & (1 << 8)) != 0)
.unwrap_or(false),
"avx512f" => crate::hardware_access::read_cpuid(7, 0)
.map(|(_, b, _, _)| (b & (1 << 16)) != 0)
.unwrap_or(false),
"sha" => crate::hardware_access::read_cpuid(7, 0)
.map(|(_, b, _, _)| (b & (1 << 29)) != 0)
.unwrap_or(false),
_ => false,
}
}
fn has_feature_arm(name: &str) -> bool {
let midr = match crate::arch::shim::read_aarch64_midr() {
Some(m) => m,
None => {
return matches!(name, "fp" | "asimd" | "neon");
}
};
let part = ((midr >> 4) & 0xfff) as u16;
let is_v81_plus = !matches!(part, 0xd03 | 0xd04 | 0xd07 | 0xd08 | 0xd09);
match name {
"fp" | "vfp" | "vfpv3" | "vfpv4" => true,
"asimd" | "neon" => true,
"crc32" => is_v81_plus,
"atomics" | "lse" => is_v81_plus,
_ => false,
}
}