#[macro_export]
macro_rules! is_x86_feature_available {
("sse") => {
$crate::__impl_feature_check!("sse")
};
("sse2") => {
$crate::__impl_feature_check!("sse2")
};
("sse3") => {
$crate::__impl_feature_check!("sse3")
};
("ssse3") => {
$crate::__impl_feature_check!("ssse3")
};
("sse4.1") => {
$crate::__impl_feature_check!("sse4.1")
};
("sse4.2") => {
$crate::__impl_feature_check!("sse4.2")
};
("avx") => {
$crate::__impl_feature_check!("avx")
};
("avx2") => {
$crate::__impl_feature_check!("avx2")
};
("fma") => {
$crate::__impl_feature_check!("fma")
};
("avx512f") => {
$crate::__impl_feature_check!("avx512f")
};
("avx512bw") => {
$crate::__impl_feature_check!("avx512bw")
};
("avx512cd") => {
$crate::__impl_feature_check!("avx512cd")
};
("avx512dq") => {
$crate::__impl_feature_check!("avx512dq")
};
("avx512vl") => {
$crate::__impl_feature_check!("avx512vl")
};
("bmi1") => {
$crate::__impl_feature_check!("bmi1")
};
("bmi2") => {
$crate::__impl_feature_check!("bmi2")
};
("popcnt") => {
$crate::__impl_feature_check!("popcnt")
};
("lzcnt") => {
$crate::__impl_feature_check!("lzcnt")
};
("pclmulqdq") => {
$crate::__impl_feature_check!("pclmulqdq")
};
("aes") => {
$crate::__impl_feature_check!("aes")
};
("sha") => {
$crate::__impl_feature_check!("sha")
};
($feature:tt) => {
$crate::__impl_runtime_only_check!($feature)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __impl_feature_check {
("sse") => {{
#[cfg(target_feature = "sse")]
{
true
}
#[cfg(not(target_feature = "sse"))]
{
$crate::__impl_runtime_only_check!("sse")
}
}};
("sse2") => {{
#[cfg(target_feature = "sse2")]
{
true
}
#[cfg(not(target_feature = "sse2"))]
{
$crate::__impl_runtime_only_check!("sse2")
}
}};
("sse3") => {{
#[cfg(target_feature = "sse3")]
{
true
}
#[cfg(not(target_feature = "sse3"))]
{
$crate::__impl_runtime_only_check!("sse3")
}
}};
("ssse3") => {{
#[cfg(target_feature = "ssse3")]
{
true
}
#[cfg(not(target_feature = "ssse3"))]
{
$crate::__impl_runtime_only_check!("ssse3")
}
}};
("sse4.1") => {{
#[cfg(target_feature = "sse4.1")]
{
true
}
#[cfg(not(target_feature = "sse4.1"))]
{
$crate::__impl_runtime_only_check!("sse4.1")
}
}};
("sse4.2") => {{
#[cfg(target_feature = "sse4.2")]
{
true
}
#[cfg(not(target_feature = "sse4.2"))]
{
$crate::__impl_runtime_only_check!("sse4.2")
}
}};
("avx") => {{
#[cfg(target_feature = "avx")]
{
true
}
#[cfg(not(target_feature = "avx"))]
{
$crate::__impl_runtime_only_check!("avx")
}
}};
("avx2") => {{
#[cfg(target_feature = "avx2")]
{
true
}
#[cfg(not(target_feature = "avx2"))]
{
$crate::__impl_runtime_only_check!("avx2")
}
}};
("fma") => {{
#[cfg(target_feature = "fma")]
{
true
}
#[cfg(not(target_feature = "fma"))]
{
$crate::__impl_runtime_only_check!("fma")
}
}};
("avx512f") => {{
#[cfg(target_feature = "avx512f")]
{
true
}
#[cfg(not(target_feature = "avx512f"))]
{
$crate::__impl_runtime_only_check!("avx512f")
}
}};
("avx512bw") => {{
#[cfg(target_feature = "avx512bw")]
{
true
}
#[cfg(not(target_feature = "avx512bw"))]
{
$crate::__impl_runtime_only_check!("avx512bw")
}
}};
("avx512cd") => {{
#[cfg(target_feature = "avx512cd")]
{
true
}
#[cfg(not(target_feature = "avx512cd"))]
{
$crate::__impl_runtime_only_check!("avx512cd")
}
}};
("avx512dq") => {{
#[cfg(target_feature = "avx512dq")]
{
true
}
#[cfg(not(target_feature = "avx512dq"))]
{
$crate::__impl_runtime_only_check!("avx512dq")
}
}};
("avx512vl") => {{
#[cfg(target_feature = "avx512vl")]
{
true
}
#[cfg(not(target_feature = "avx512vl"))]
{
$crate::__impl_runtime_only_check!("avx512vl")
}
}};
("bmi1") => {{
#[cfg(target_feature = "bmi1")]
{
true
}
#[cfg(not(target_feature = "bmi1"))]
{
$crate::__impl_runtime_only_check!("bmi1")
}
}};
("bmi2") => {{
#[cfg(target_feature = "bmi2")]
{
true
}
#[cfg(not(target_feature = "bmi2"))]
{
$crate::__impl_runtime_only_check!("bmi2")
}
}};
("popcnt") => {{
#[cfg(target_feature = "popcnt")]
{
true
}
#[cfg(not(target_feature = "popcnt"))]
{
$crate::__impl_runtime_only_check!("popcnt")
}
}};
("lzcnt") => {{
#[cfg(target_feature = "lzcnt")]
{
true
}
#[cfg(not(target_feature = "lzcnt"))]
{
$crate::__impl_runtime_only_check!("lzcnt")
}
}};
("pclmulqdq") => {{
#[cfg(target_feature = "pclmulqdq")]
{
true
}
#[cfg(not(target_feature = "pclmulqdq"))]
{
$crate::__impl_runtime_only_check!("pclmulqdq")
}
}};
("aes") => {{
#[cfg(target_feature = "aes")]
{
true
}
#[cfg(not(target_feature = "aes"))]
{
$crate::__impl_runtime_only_check!("aes")
}
}};
("sha") => {{
#[cfg(target_feature = "sha")]
{
true
}
#[cfg(not(target_feature = "sha"))]
{
$crate::__impl_runtime_only_check!("sha")
}
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __impl_runtime_only_check {
($feature:tt) => {{
#[cfg(target_arch = "x86_64")]
{
#[cfg(feature = "std")]
{
std::arch::is_x86_feature_detected!($feature)
}
#[cfg(not(feature = "std"))]
{
false
}
}
#[cfg(target_arch = "x86")]
{
#[cfg(feature = "std")]
{
std::arch::is_x86_feature_detected!($feature)
}
#[cfg(not(feature = "std"))]
{
false
}
}
#[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))]
{
false
}
}};
}
#[macro_export]
macro_rules! is_aarch64_feature_available {
("neon") => {{ $crate::__impl_aarch64_feature_check!("neon") }};
("sve") => {{ $crate::__impl_aarch64_feature_check!("sve") }};
("sve2") => {{ $crate::__impl_aarch64_feature_check!("sve2") }};
("aes") => {{ $crate::__impl_aarch64_feature_check!("aes") }};
("sha2") => {{ $crate::__impl_aarch64_feature_check!("sha2") }};
("sha3") => {{ $crate::__impl_aarch64_feature_check!("sha3") }};
("crc") => {{ $crate::__impl_aarch64_feature_check!("crc") }};
("dotprod") => {{ $crate::__impl_aarch64_feature_check!("dotprod") }};
("rdm") => {{ $crate::__impl_aarch64_feature_check!("rdm") }};
("fp16") => {{ $crate::__impl_aarch64_feature_check!("fp16") }};
("fhm") => {{ $crate::__impl_aarch64_feature_check!("fhm") }};
("fcma") => {{ $crate::__impl_aarch64_feature_check!("fcma") }};
("i8mm") => {{ $crate::__impl_aarch64_feature_check!("i8mm") }};
("bf16") => {{ $crate::__impl_aarch64_feature_check!("bf16") }};
($feature:tt) => {{ $crate::__impl_aarch64_runtime_only_check!($feature) }};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __impl_aarch64_feature_check {
("neon") => {{
#[cfg(target_feature = "neon")]
{
true
}
#[cfg(not(target_feature = "neon"))]
{
$crate::__impl_aarch64_apple_or_runtime_check!("neon")
}
}};
("aes") => {{
#[cfg(target_feature = "aes")]
{
true
}
#[cfg(not(target_feature = "aes"))]
{
$crate::__impl_aarch64_apple_or_runtime_check!("aes")
}
}};
("sha2") => {{
#[cfg(target_feature = "sha2")]
{
true
}
#[cfg(not(target_feature = "sha2"))]
{
$crate::__impl_aarch64_apple_or_runtime_check!("sha2")
}
}};
("sha3") => {{
#[cfg(target_feature = "sha3")]
{
true
}
#[cfg(not(target_feature = "sha3"))]
{
$crate::__impl_aarch64_apple_or_runtime_check!("sha3")
}
}};
("crc") => {{
#[cfg(target_feature = "crc")]
{
true
}
#[cfg(not(target_feature = "crc"))]
{
$crate::__impl_aarch64_apple_or_runtime_check!("crc")
}
}};
("dotprod") => {{
#[cfg(target_feature = "dotprod")]
{
true
}
#[cfg(not(target_feature = "dotprod"))]
{
$crate::__impl_aarch64_apple_or_runtime_check!("dotprod")
}
}};
("rdm") => {{
#[cfg(target_feature = "rdm")]
{
true
}
#[cfg(not(target_feature = "rdm"))]
{
$crate::__impl_aarch64_apple_or_runtime_check!("rdm")
}
}};
("fp16") => {{
#[cfg(target_feature = "fp16")]
{
true
}
#[cfg(not(target_feature = "fp16"))]
{
$crate::__impl_aarch64_apple_or_runtime_check!("fp16")
}
}};
("fhm") => {{
#[cfg(target_feature = "fhm")]
{
true
}
#[cfg(not(target_feature = "fhm"))]
{
$crate::__impl_aarch64_apple_or_runtime_check!("fhm")
}
}};
("fcma") => {{
#[cfg(target_feature = "fcma")]
{
true
}
#[cfg(not(target_feature = "fcma"))]
{
$crate::__impl_aarch64_apple_or_runtime_check!("fcma")
}
}};
("sve") => {{
#[cfg(target_feature = "sve")]
{
true
}
#[cfg(not(target_feature = "sve"))]
{
$crate::__impl_aarch64_runtime_only_check!("sve")
}
}};
("sve2") => {{
#[cfg(target_feature = "sve2")]
{
true
}
#[cfg(not(target_feature = "sve2"))]
{
$crate::__impl_aarch64_runtime_only_check!("sve2")
}
}};
("i8mm") => {{
#[cfg(target_feature = "i8mm")]
{
true
}
#[cfg(not(target_feature = "i8mm"))]
{
$crate::__impl_aarch64_runtime_only_check!("i8mm")
}
}};
("bf16") => {{
#[cfg(target_feature = "bf16")]
{
true
}
#[cfg(not(target_feature = "bf16"))]
{
$crate::__impl_aarch64_runtime_only_check!("bf16")
}
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __impl_aarch64_apple_or_runtime_check {
($feature:tt) => {{
#[cfg(all(target_vendor = "apple", target_arch = "aarch64"))]
{
true
}
#[cfg(not(all(target_vendor = "apple", target_arch = "aarch64")))]
{
$crate::__impl_aarch64_runtime_only_check!($feature)
}
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __impl_aarch64_runtime_only_check {
($feature:tt) => {{
#[cfg(target_arch = "aarch64")]
{
#[cfg(feature = "std")]
{
std::arch::is_aarch64_feature_detected!($feature)
}
#[cfg(not(feature = "std"))]
{
false
}
}
#[cfg(not(target_arch = "aarch64"))]
{
false
}
}};
}
#[cfg(target_arch = "x86_64")]
#[inline(never)]
pub fn check_avx2_available() -> bool {
is_x86_feature_available!("avx2")
}
#[cfg(target_arch = "x86_64")]
#[inline(never)]
pub fn check_fma_available() -> bool {
is_x86_feature_available!("fma")
}
#[cfg(target_arch = "x86_64")]
#[inline(never)]
pub fn check_avx512f_available() -> bool {
is_x86_feature_available!("avx512f")
}
#[cfg(target_arch = "aarch64")]
#[inline(never)]
pub fn check_sve_available() -> bool {
is_aarch64_feature_available!("sve")
}
#[cfg(target_arch = "aarch64")]
#[inline(never)]
pub fn check_sve2_available() -> bool {
is_aarch64_feature_available!("sve2")
}
#[cfg(test)]
mod tests {
#[test]
fn test_all_features_compile() {
let _ = is_x86_feature_available!("sse");
let _ = is_x86_feature_available!("sse2");
let _ = is_x86_feature_available!("sse3");
let _ = is_x86_feature_available!("ssse3");
let _ = is_x86_feature_available!("sse4.1");
let _ = is_x86_feature_available!("sse4.2");
let _ = is_x86_feature_available!("avx");
let _ = is_x86_feature_available!("avx2");
let _ = is_x86_feature_available!("fma");
let _ = is_x86_feature_available!("avx512f");
let _ = is_x86_feature_available!("avx512bw");
let _ = is_x86_feature_available!("bmi1");
let _ = is_x86_feature_available!("bmi2");
let _ = is_x86_feature_available!("popcnt");
let _ = is_x86_feature_available!("lzcnt");
let _ = is_x86_feature_available!("aes");
}
#[test]
#[cfg(target_arch = "x86_64")]
fn test_sse2_always_available() {
let has_sse2 = is_x86_feature_available!("sse2");
assert!(has_sse2);
}
#[test]
#[cfg(all(target_arch = "x86_64", feature = "std"))]
fn test_matches_std_detection() {
use std::arch::is_x86_feature_detected;
assert_eq!(
is_x86_feature_available!("avx2"),
is_x86_feature_detected!("avx2")
);
assert_eq!(
is_x86_feature_available!("fma"),
is_x86_feature_detected!("fma")
);
assert_eq!(
is_x86_feature_available!("avx512f"),
is_x86_feature_detected!("avx512f")
);
}
#[test]
#[cfg(target_feature = "avx2")]
fn test_compile_time_avx2() {
assert!(is_x86_feature_available!("avx2"));
}
#[test]
#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))]
fn test_compile_time_sse2() {
let has_sse2 = is_x86_feature_available!("sse2");
assert!(has_sse2);
}
#[test]
#[cfg(target_arch = "aarch64")]
fn test_aarch64_features_compile() {
let _ = is_aarch64_feature_available!("neon");
let _ = is_aarch64_feature_available!("sve");
let _ = is_aarch64_feature_available!("sve2");
}
#[test]
#[cfg(target_arch = "aarch64")]
fn test_neon_detection() {
let has_neon = is_aarch64_feature_available!("neon");
let _ = has_neon;
}
#[test]
#[cfg(all(target_arch = "aarch64", feature = "std"))]
fn test_aarch64_matches_std_detection() {
use std::arch::is_aarch64_feature_detected;
assert_eq!(
is_aarch64_feature_available!("sve"),
is_aarch64_feature_detected!("sve")
);
assert_eq!(
is_aarch64_feature_available!("sve2"),
is_aarch64_feature_detected!("sve2")
);
}
}