// Copyright (c) the JPEG XL Project Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#! [allow(unsafe_code)]
#! [allow(clippy::identity_op)]
#[ cfg(feature = "avx" )]
pub (super ) mod avx;
#[ cfg(feature = "avx512" )]
pub (super ) mod avx512;
#[ cfg(feature = "sse42" )]
pub (super ) mod sse42;
#[ macro_export]
macro_rules! simd_function {
(
$dname:ident,
$descr:ident: $descr_ty:ident,
$(#[ $($attr:meta)*])*
$pub :vis fn $name:ident($($arg:ident: $ty:ty),* $(,)?) $(-> $ret:ty )? $body: block
) => {
#[ inline(always)]
$(#[ $($attr)*])*
$pub fn $name<$descr_ty: $crate ::SimdDescriptor>($descr: $descr_ty, $($arg: $ty),*) $(-> $ret)? $body
#[ allow(unsafe_code)]
$(#[ $($attr)*])*
$pub fn $dname($($arg: $ty),*) $(-> $ret)? {
#[ allow(unused)]
use $crate ::SimdDescriptor;
$crate ::simd_function_body_avx512!($name($($arg: $ty),*) $(-> $ret)?; ($($arg),*));
$crate ::simd_function_body_avx!($name($($arg: $ty),*) $(-> $ret)?; ($($arg),*));
$crate ::simd_function_body_sse42!($name($($arg: $ty),*) $(-> $ret)?; ($($arg),*));
$name($crate ::ScalarDescriptor::new().unwrap(), $($arg),*)
}
};
}
#[ cfg(feature = "sse42" )]
#[ doc(hidden)]
#[ macro_export]
macro_rules! simd_function_body_sse42 {
($name:ident($($arg:ident: $ty:ty),* $(,)?) $(-> $ret:ty )?; ($($val:expr),* $(,)?)) => {
if cfg!(target_feature = "sse4.2" ) {
// SAFETY: we just checked for sse4.2.
let d = unsafe { $crate ::Sse42Descriptor::new_unchecked() };
return $name(d, $($val),*);
} else if let Some(d) = $crate ::Sse42Descriptor::new() {
#[ target_feature(enable = "sse4.2" )]
fn sse42(d: $crate ::Sse42Descriptor, $($arg: $ty),*) $(-> $ret)? {
$name(d, $($val),*)
}
// SAFETY: we just checked for sse4.2.
return unsafe { sse42(d, $($arg),*) };
}
};
}
#[ cfg(feature = "avx" )]
#[ doc(hidden)]
#[ macro_export]
macro_rules! simd_function_body_avx {
($name:ident($($arg:ident: $ty:ty),* $(,)?) $(-> $ret:ty )?; ($($val:expr),* $(,)?)) => {
if cfg!(all(target_feature = "avx2" , target_feature = "fma" , target_feature = "f16c" )) {
// SAFETY: we just checked for avx2, fma and f16c.
let d = unsafe { $crate ::AvxDescriptor::new_unchecked() };
return $name(d, $($val),*);
} else if let Some(d) = $crate ::AvxDescriptor::new() {
#[ target_feature(enable = "avx2,fma,f16c" )]
fn avx(d: $crate ::AvxDescriptor, $($arg: $ty),*) $(-> $ret)? {
$name(d, $($val),*)
}
// SAFETY: we just checked for avx2, fma and f16c.
return unsafe { avx(d, $($arg),*) };
}
};
}
#[ cfg(feature = "avx512" )]
#[ doc(hidden)]
#[ macro_export]
macro_rules! simd_function_body_avx512 {
($name:ident($($arg:ident: $ty:ty),* $(,)?) $(-> $ret:ty )?; ($($val:expr),* $(,)?)) => {
if cfg!(target_feature = "avx512f" ) {
// SAFETY: we just checked for avx512f.
let d = unsafe { $crate ::Avx512Descriptor::new_unchecked() };
return $name(d, $($val),*);
} else if let Some(d) = $crate ::Avx512Descriptor::new() {
#[ target_feature(enable = "avx512f" )]
fn avx512(d: $crate ::Avx512Descriptor, $($arg: $ty),*) $(-> $ret)? {
$name(d, $($val),*)
}
// SAFETY: we just checked for avx512f.
return unsafe { avx512(d, $($arg),*) };
}
};
}
#[ cfg(not(feature = "sse42" ))]
#[ doc(hidden)]
#[ macro_export]
macro_rules! simd_function_body_sse42 {
($($ignore:tt)*) => {};
}
#[ cfg(not(feature = "avx" ))]
#[ doc(hidden)]
#[ macro_export]
macro_rules! simd_function_body_avx {
($($ignore:tt)*) => {};
}
#[ cfg(not(feature = "avx512" ))]
#[ doc(hidden)]
#[ macro_export]
macro_rules! simd_function_body_avx512 {
($($ignore:tt)*) => {};
}
#[ macro_export]
macro_rules! test_all_instruction_sets {
(
$name:ident
) => {
paste::paste! {
#[ test]
fn [<$name _scalar>]() {
use $crate ::SimdDescriptor;
$name($crate ::ScalarDescriptor::new().unwrap())
}
}
$crate ::test_sse42!($name);
$crate ::test_avx!($name);
$crate ::test_avx512!($name);
};
}
#[ cfg(feature = "sse42" )]
#[ doc(hidden)]
#[ macro_export]
macro_rules! test_sse42 {
($name:ident) => {
paste::paste! {
#[ allow(unsafe_code)]
#[ test]
fn [<$name _sse42>]() {
use $crate ::SimdDescriptor;
let Some(d) = $crate ::Sse42Descriptor::new() else { return ; };
#[ target_feature(enable = "sse4.2" )]
fn inner(d: $crate ::Sse42Descriptor) {
$name(d)
}
// SAFETY: we just checked for sse4.2.
return unsafe { inner(d) };
}
}
};
}
#[ cfg(feature = "avx" )]
#[ doc(hidden)]
#[ macro_export]
macro_rules! test_avx {
($name:ident) => {
paste::paste! {
#[ allow(unsafe_code)]
#[ test]
fn [<$name _avx>]() {
use $crate ::SimdDescriptor;
let Some(d) = $crate ::AvxDescriptor::new() else { return ; };
#[ target_feature(enable = "avx2,fma,f16c" )]
fn inner(d: $crate ::AvxDescriptor) {
$name(d)
}
// SAFETY: we just checked for avx2, fma and f16c.
return unsafe { inner(d) };
}
}
};
}
#[ cfg(feature = "avx512" )]
#[ doc(hidden)]
#[ macro_export]
macro_rules! test_avx512 {
($name:ident) => {
paste::paste! {
#[ allow(unsafe_code)]
#[ test]
fn [<$name _avx512>]() {
use $crate ::SimdDescriptor;
let Some(d) = $crate ::Avx512Descriptor::new() else { return ; };
#[ target_feature(enable = "avx512f" )]
fn inner(d: $crate ::Avx512Descriptor) {
$name(d)
}
// SAFETY: we just checked for avx512f.
return unsafe { inner(d) };
}
}
};
}
#[ cfg(not(feature = "sse42" ))]
#[ doc(hidden)]
#[ macro_export]
macro_rules! test_sse42 {
($name:ident) => {};
}
#[ cfg(not(feature = "avx" ))]
#[ doc(hidden)]
#[ macro_export]
macro_rules! test_avx {
($name:ident) => {};
}
#[ cfg(not(feature = "avx512" ))]
#[ doc(hidden)]
#[ macro_export]
macro_rules! test_avx512 {
($name:ident) => {};
}
#[ macro_export]
macro_rules! bench_all_instruction_sets {
(
$name:ident,
$criterion:ident
) => {
#[ allow(unused)]
use $crate ::SimdDescriptor;
// `simd_function_body_*` does early return; wrap it with an immediately-invoked closure
(|| {
$crate ::simd_function_body_avx512!(
$name($criterion: &mut ::criterion::BenchmarkGroup<'_, impl ::criterion::measurement::Measurement>);
($criterion, "avx512" )
);
})();
(|| {
$crate ::simd_function_body_avx!(
$name($criterion: &mut ::criterion::BenchmarkGroup<'_, impl ::criterion::measurement::Measurement>);
($criterion, "avx" )
);
})();
(|| {
$crate ::simd_function_body_sse42!(
$name($criterion: &mut ::criterion::BenchmarkGroup<'_, impl ::criterion::measurement::Measurement>);
($criterion, "sse42" )
);
})();
$name(
$crate ::ScalarDescriptor::new().unwrap(),
$criterion,
"scalar" ,
);
};
}
Messung V0.5 in Prozent C=95 H=84 G=89
¤ Dauer der Verarbeitung: 0.5 Sekunden
¤
*© Formatika GbR, Deutschland