#[macro_export]
macro_rules! simd_dispatch {
(avx512 => $avx512:expr, avx2 => $avx2:expr, sse2 => $sse2:expr, _ => $fallback:expr) => {{
#[cfg(target_arch = "x86_64")]
{
#[cfg(feature = "avx512")]
{
if ::std::is_x86_feature_detected!("avx512f")
&& ::std::is_x86_feature_detected!("avx512bw")
{
return $avx512;
}
}
if ::std::is_x86_feature_detected!("avx2") {
return $avx2;
}
if ::std::is_x86_feature_detected!("sse2") {
return $sse2;
}
}
#[cfg(target_arch = "aarch64")]
{
return $sse2;
}
$fallback
}};
(avx2 => $avx2:expr, sse2 => $sse2:expr, _ => $fallback:expr) => {{
#[cfg(target_arch = "x86_64")]
{
if ::std::is_x86_feature_detected!("avx2") {
return $avx2;
}
if ::std::is_x86_feature_detected!("sse2") {
return $sse2;
}
}
#[cfg(target_arch = "aarch64")]
{
return $sse2;
}
$fallback
}};
(avx2_bmi2 => $avx2_bmi2:expr, avx2 => $avx2:expr, _ => $fallback:expr) => {{
#[cfg(target_arch = "x86_64")]
{
if ::std::is_x86_feature_detected!("avx2")
&& ::std::is_x86_feature_detected!("bmi2")
{
return $avx2_bmi2;
}
if ::std::is_x86_feature_detected!("avx2") {
return $avx2;
}
}
$fallback
}};
(avx2 => $avx2:expr, _ => $fallback:expr) => {{
#[cfg(target_arch = "x86_64")]
{
if ::std::is_x86_feature_detected!("avx2") {
return $avx2;
}
}
$fallback
}};
(sse42 => $sse42:expr, _ => $fallback:expr) => {{
#[cfg(target_arch = "x86_64")]
{
if ::std::is_x86_feature_detected!("sse4.2") {
return $sse42;
}
}
$fallback
}};
(bmi2 => $bmi2:expr, _ => $fallback:expr) => {{
#[cfg(target_arch = "x86_64")]
{
if ::std::is_x86_feature_detected!("bmi2") {
return $bmi2;
}
}
$fallback
}};
(popcnt => $popcnt:expr, _ => $fallback:expr) => {{
#[cfg(target_arch = "x86_64")]
{
if ::std::is_x86_feature_detected!("popcnt") {
return $popcnt;
}
}
$fallback
}};
(
avx512 => $avx512:expr,
avx2_bmi2 => $avx2_bmi2:expr,
avx2 => $avx2:expr,
sse42_bmi2 => $sse42_bmi2:expr,
sse42 => $sse42:expr,
bmi2 => $bmi2:expr,
_ => $fallback:expr
) => {{
#[cfg(target_arch = "x86_64")]
{
#[cfg(feature = "avx512")]
{
if ::std::is_x86_feature_detected!("avx512f")
&& ::std::is_x86_feature_detected!("avx512bw")
{
return $avx512;
}
}
if ::std::is_x86_feature_detected!("avx2")
&& ::std::is_x86_feature_detected!("bmi2")
{
return $avx2_bmi2;
}
if ::std::is_x86_feature_detected!("avx2") {
return $avx2;
}
if ::std::is_x86_feature_detected!("sse4.2")
&& ::std::is_x86_feature_detected!("bmi2")
{
return $sse42_bmi2;
}
if ::std::is_x86_feature_detected!("sse4.2") {
return $sse42;
}
if ::std::is_x86_feature_detected!("bmi2") {
return $bmi2;
}
}
$fallback
}};
}
#[macro_export]
macro_rules! simd_feature_check {
($feature:tt, $simd_expr:expr, $fallback:expr) => {{
#[cfg(target_arch = "x86_64")]
{
if ::std::is_x86_feature_detected!($feature) {
return $simd_expr;
}
}
$fallback
}};
($feat1:tt, $feat2:tt, $simd_expr:expr, $fallback:expr) => {{
#[cfg(target_arch = "x86_64")]
{
if ::std::is_x86_feature_detected!($feat1)
&& ::std::is_x86_feature_detected!($feat2)
{
return $simd_expr;
}
}
$fallback
}};
}
#[macro_export]
macro_rules! simd_select {
(avx2 => $avx2:expr, _ => $fallback:expr) => {{
#[cfg(target_arch = "x86_64")]
{
if ::std::is_x86_feature_detected!("avx2") {
$avx2
} else {
$fallback
}
}
#[cfg(not(target_arch = "x86_64"))]
{
$fallback
}
}};
(avx2 => $avx2:expr, sse2 => $sse2:expr, _ => $fallback:expr) => {{
#[cfg(target_arch = "x86_64")]
{
if ::std::is_x86_feature_detected!("avx2") {
$avx2
} else if ::std::is_x86_feature_detected!("sse2") {
$sse2
} else {
$fallback
}
}
#[cfg(not(target_arch = "x86_64"))]
{
$fallback
}
}};
($feature:ident => $simd:expr, _ => $fallback:expr) => {{
#[cfg(target_arch = "x86_64")]
{
if ::std::is_x86_feature_detected!(stringify!($feature)) {
$simd
} else {
$fallback
}
}
#[cfg(not(target_arch = "x86_64"))]
{
$fallback
}
}};
}
#[macro_export]
macro_rules! simd_available {
($feature:tt) => {{
#[cfg(target_arch = "x86_64")]
{
::std::is_x86_feature_detected!($feature)
}
#[cfg(not(target_arch = "x86_64"))]
{
false
}
}};
($feat1:tt, $feat2:tt) => {{
#[cfg(target_arch = "x86_64")]
{
::std::is_x86_feature_detected!($feat1)
&& ::std::is_x86_feature_detected!($feat2)
}
#[cfg(not(target_arch = "x86_64"))]
{
false
}
}};
}
#[cfg(test)]
#[cfg(target_arch = "x86_64")]
mod tests {
#[test]
fn test_simd_available_macro() {
let _has_sse2 = std::is_x86_feature_detected!("sse2");
let _has_avx2 = std::is_x86_feature_detected!("avx2");
let _has_bmi2 = std::is_x86_feature_detected!("bmi2");
assert!(_has_sse2); }
#[test]
fn test_simd_select_macro() {
fn scalar_impl() -> i32 {
42
}
fn avx2_impl() -> i32 {
84
}
let result = crate::simd_select!(
avx2 => avx2_impl(),
_ => scalar_impl()
);
assert!(result == 42 || result == 84);
}
#[test]
fn test_simd_select_with_sse2() {
fn scalar_impl() -> i32 {
1
}
fn sse2_impl() -> i32 {
2
}
fn avx2_impl() -> i32 {
3
}
let result = crate::simd_select!(
avx2 => avx2_impl(),
sse2 => sse2_impl(),
_ => scalar_impl()
);
assert!(result >= 1 && result <= 3);
}
fn dispatch_test_fn(val: i32) -> i32 {
crate::simd_dispatch!(
avx2 => val * 2,
sse2 => val + 10,
_ => val
)
}
#[test]
fn test_simd_dispatch_macro() {
let result = dispatch_test_fn(5);
assert!(result == 10 || result == 15 || result == 5);
}
fn feature_check_test_fn(val: i32) -> i32 {
crate::simd_feature_check!(
"avx2",
val * 3,
val
)
}
#[test]
fn test_simd_feature_check_macro() {
let result = feature_check_test_fn(7);
assert!(result == 21 || result == 7);
}
fn dual_feature_test_fn(val: i32) -> i32 {
crate::simd_feature_check!(
"avx2", "bmi2",
val * 4,
val
)
}
#[test]
fn test_dual_feature_check_macro() {
let result = dual_feature_test_fn(5);
assert!(result == 20 || result == 5);
}
}