mirror of
https://git.vladimir.cc/vladimir/wdsp.git
synced 2026-08-25 17:27:33 +00:00
resample: vectorize the polyphase tap loop
The tap loop wrapped the ring with a test on every tap:
if ((idx_out = idx_in + j) >= ringsize) idx_out -= ringsize;
which made the address non-affine and stopped the vectorizer. Split the
walk at the wrap point instead, so both halves are unit-stride, and split
the complex ring into separate I/Q arrays so the taps load contiguously
rather than through a de-interleaving ld2.
The dot product also could not be vectorized as written: reassociating an
fp reduction needs -ffast-math, which this library must not enable (it
relies on IEEE semantics for 0/0 = NaN and x/0 = Inf, see linux_port.h).
Carry four independent accumulator pairs instead, which both breaks the
FMA dependency chain and lets the vectorizer in on any compiler.
Measured on an Apple M1 Pro, 512-sample DSP buffers, best of 5:
xresample, decimation to 48 kHz before after speedup
192k -> 48k (561 taps) 342.0 us 84.2 us 4.06x
384k -> 48k (1121 taps) 708.9 us 175.1 us 4.05x
576k -> 48k (1681 taps) 1074.4 us 266.9 us 4.03x
768k -> 48k (2241 taps) 1438.9 us 360.0 us 4.00x
full xrxa() chain, 576k input 1148.2 us 337.6 us 3.40x
10.76% 3.16% of one core
xresampleF (float, host audio) 2.6x - 3.4x
Summation order changes, so the double path is not bit-identical: over
400 buffers of the full RX chain the worst deviation is 1.1e-12, an SNR
of 251 dB. The float path is bit-identical, as the cast to float absorbs
the difference. With the resampler bypassed (48k in, 48k out) the chain
is unchanged bit-for-bit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
89c8a0e2b5
commit
9960a1d0e3
+3
-1
@@ -52,7 +52,9 @@ typedef struct _resample
|
||||
int M; // decimation factor
|
||||
double* h; // coefficients
|
||||
int ringsize; // number of complex pairs the ring buffer holds
|
||||
double* ring; // ring buffer
|
||||
double* ringI; // ring buffer, in-phase
|
||||
double* ringQ; // ring buffer, quadrature (split from I so the tap loop
|
||||
// reads unit-stride and vectorizes)
|
||||
int cpp; // coefficients of the phase
|
||||
int phnum; // phase number
|
||||
} resample, *RESAMPLE;
|
||||
|
||||
Reference in New Issue
Block a user