#![cfg_attr(
not(any(target_arch = "x86_64", target_arch = "aarch64")),
allow(dead_code, unused_imports)
)]
pub mod bench;
mod imdct;
mod kernels;
mod vector;
#[cfg(test)]
mod tests;
pub(crate) use imdct::Imdct;
use crate::simd::SimdIsa;
use imdct::Plan;
use kernels::Scratch;
#[must_use]
#[doc(hidden)]
pub fn active_isa() -> SimdIsa {
crate::simd::active()
}
macro_rules! entry_points {
(
fn [$sse:ident, $avx:ident, $neon:ident]($($arg:ident : $ty:ty),* $(,)?)
= [$sse_kernel:expr, $avx_kernel:expr, $neon_kernel:expr];
) => {
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "sse4.1")]
#[inline(never)]
unsafe fn $sse($($arg: $ty),*) {
unsafe { $sse_kernel($($arg),*) }
}
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "avx2")]
#[inline(never)]
unsafe fn $avx($($arg: $ty),*) {
unsafe { $avx_kernel($($arg),*) }
}
#[cfg(target_arch = "aarch64")]
#[target_feature(enable = "neon")]
#[inline(never)]
unsafe fn $neon($($arg: $ty),*) {
unsafe { $neon_kernel($($arg),*) }
}
};
}
entry_points! {
fn [imdct_sse41, imdct_avx2, imdct_neon](
plan: &Plan, spec: &[f32], out: &mut [f32], scratch: Scratch<'_>
) = [
kernels::imdct::<vector::Sse4, vector::Sse4>,
kernels::imdct::<vector::Avx2, vector::Sse4>,
kernels::imdct::<vector::Neon, vector::Neon>
];
}
entry_points! {
fn [overlap_add_sse41, overlap_add_avx2, overlap_add_neon](
out: &mut [f32], left: &[f32], right: &[f32], win: &[f32], win_rev: &[f32]
) = [
kernels::overlap_add::<vector::Sse4>,
kernels::overlap_add::<vector::Avx2>,
kernels::overlap_add::<vector::Neon>
];
}
entry_points! {
fn [clamp_unit_sse41, clamp_unit_avx2, clamp_unit_neon](buf: &mut [f32]) = [
kernels::clamp_unit::<vector::Sse4>,
kernels::clamp_unit::<vector::Avx2>,
kernels::clamp_unit::<vector::Neon>
];
}
entry_points! {
fn [coupling_sse41, coupling_avx2, coupling_neon](magnitude: &mut [f32], angle: &mut [f32]) = [
kernels::inverse_coupling::<vector::Sse4>,
kernels::inverse_coupling::<vector::Avx2>,
kernels::inverse_coupling::<vector::Neon>
];
}
entry_points! {
fn [apply_floor_sse41, apply_floor_avx2, apply_floor_neon](floor: &mut [f32], residue: &[f32]) = [
kernels::apply_floor::<vector::Sse4>,
kernels::apply_floor::<vector::Avx2>,
kernels::apply_floor::<vector::Neon>
];
}
macro_rules! dispatch {
($isa:expr, [$sse:ident, $avx:ident, $neon:ident], $scalar:path, ($($arg:expr),*)) => {
match $isa {
#[cfg(target_arch = "x86_64")]
SimdIsa::Avx2 => unsafe { $avx($($arg),*) },
#[cfg(target_arch = "x86_64")]
SimdIsa::Sse41 => unsafe { $sse($($arg),*) },
#[cfg(target_arch = "aarch64")]
SimdIsa::Neon => unsafe { $neon($($arg),*) },
_ => $scalar($($arg),*),
}
};
}
pub(crate) fn overlap_add(
out: &mut [f32],
left: &[f32],
right: &[f32],
win: &[f32],
win_rev: &[f32],
) {
overlap_add_with(active_isa(), out, left, right, win, win_rev);
}
pub(crate) fn overlap_add_with(
isa: SimdIsa,
out: &mut [f32],
left: &[f32],
right: &[f32],
win: &[f32],
win_rev: &[f32],
) {
let len = out.len();
assert!(left.len() == len && right.len() == len && win.len() == len && win_rev.len() == len);
dispatch!(
isa,
[overlap_add_sse41, overlap_add_avx2, overlap_add_neon],
kernels::overlap_add_scalar,
(out, left, right, win, win_rev)
);
}
pub(crate) fn clamp_unit(buf: &mut [f32]) {
clamp_unit_with(active_isa(), buf);
}
pub(crate) fn clamp_unit_with(isa: SimdIsa, buf: &mut [f32]) {
dispatch!(
isa,
[clamp_unit_sse41, clamp_unit_avx2, clamp_unit_neon],
kernels::clamp_unit_scalar,
(buf)
);
}
pub(crate) fn inverse_coupling(magnitude: &mut [f32], angle: &mut [f32]) {
inverse_coupling_with(active_isa(), magnitude, angle);
}
pub(crate) fn inverse_coupling_with(isa: SimdIsa, magnitude: &mut [f32], angle: &mut [f32]) {
assert_eq!(magnitude.len(), angle.len());
dispatch!(
isa,
[coupling_sse41, coupling_avx2, coupling_neon],
kernels::inverse_coupling_scalar,
(magnitude, angle)
);
}
pub(crate) fn apply_floor(floor: &mut [f32], residue: &[f32]) {
apply_floor_with(active_isa(), floor, residue);
}
pub(crate) fn apply_floor_with(isa: SimdIsa, floor: &mut [f32], residue: &[f32]) {
assert_eq!(floor.len(), residue.len());
dispatch!(
isa,
[apply_floor_sse41, apply_floor_avx2, apply_floor_neon],
kernels::apply_floor_scalar,
(floor, residue)
);
}