phrot, cfcomp: cascade in a register; drop idiv from cfcomp's ring walks
xphrot() kept x0[] and y0[] in the struct, but neither carried state between
samples: x0[n] was always the previous stage's output and y0[n] this stage's.
Cascade that single value in a register and leave x1/y1 as the real filter
state. Stores through out[] may alias the struct's doubles, so hoist the
coefficients as well. Eight first-order sections then run without touching
memory except for the state.
xcfcomp() is structurally the same overlap-add loop as xemnr(), and had the
same defect: four ring indices advanced with '% size' per step, ~5100 integer
divisions per call at fsize = 2048, which a profile showed dominating the
block (1820 samples in xcfcomp against 362 in calc_mask and ~520 in the FFTs).
The indices step by one, and iasize >= fsize and oasize >= incr always hold,
so they wrap at most once per loop: walk contiguous runs and wrap between them.
Measured in situ on an Apple M1 Pro, 512-sample buffers, cost of turning the
block on, best of 5:
phrot 17219 ns -> 7047 ns 2.44x
cfcomp 28918 ns -> 13637 ns 2.12x
Both are bit-identical: phrot preserves the operation order, and cfcomp only
changes integer index arithmetic. The RX chain is unchanged bit-for-bit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -616,19 +616,31 @@ void xphrot (PHROT a)
|
||||
if (a->run)
|
||||
{
|
||||
int i, n;
|
||||
for (i = 0; i < a->size; i++)
|
||||
const int size = a->size;
|
||||
const int nstages = a->nstages;
|
||||
const double b0 = a->b0, b1 = a->b1, a1 = a->a1;
|
||||
/* in and out are the same buffer in TXA, so neither may be restrict */
|
||||
const double* in = a->in;
|
||||
double* out = a->out;
|
||||
/* x0[]/y0[] never carried state between samples: x0[n] was only ever the
|
||||
previous stage's output and y0[n] this stage's. Keep that single value
|
||||
in a register and cascade it, leaving x1/y1 as the actual filter state.
|
||||
Stores through out[] could alias the struct's doubles, so hoist the
|
||||
coefficients too. */
|
||||
double* WDSP_RESTRICT x1 = a->x1;
|
||||
double* WDSP_RESTRICT y1 = a->y1;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
a->x0[0] = a->in[2 * i + 0];
|
||||
for (n = 0; n < a->nstages; n++)
|
||||
double v = in[2 * i + 0];
|
||||
for (n = 0; n < nstages; n++)
|
||||
{
|
||||
if (n > 0) a->x0[n] = a->y0[n - 1];
|
||||
a->y0[n] = a->b0 * a->x0[n]
|
||||
+ a->b1 * a->x1[n]
|
||||
- a->a1 * a->y1[n];
|
||||
a->y1[n] = a->y0[n];
|
||||
a->x1[n] = a->x0[n];
|
||||
double y = b0 * v + b1 * x1[n] - a1 * y1[n];
|
||||
x1[n] = v;
|
||||
y1[n] = y;
|
||||
v = y;
|
||||
}
|
||||
a->out[2 * i + 0] = a->y0[a->nstages - 1];
|
||||
out[2 * i + 0] = v;
|
||||
}
|
||||
}
|
||||
else if (a->out != a->in)
|
||||
|
||||
Reference in New Issue
Block a user