77inline void addWithGain(
float* DSPARK_RESTRICT dst,
const float* DSPARK_RESTRICT src,
float gain,
int count)
noexcept
79#if defined(DSPARK_SIMD_AVX)
80 const __m256 vGain = _mm256_set1_ps(gain);
82 for (; i + 7 < count; i += 8)
84 __m256 vDst = _mm256_loadu_ps(dst + i);
85 __m256 vSrc = _mm256_loadu_ps(src + i);
87 #if defined(DSPARK_SIMD_FMA)
88 _mm256_storeu_ps(dst + i, _mm256_fmadd_ps(vSrc, vGain, vDst));
90 _mm256_storeu_ps(dst + i, _mm256_add_ps(vDst, _mm256_mul_ps(vSrc, vGain)));
93 for (; i < count; ++i) dst[i] += src[i] * gain;
95#elif defined(DSPARK_SIMD_SSE2)
96 const __m128 vGain = _mm_set1_ps(gain);
98 for (; i + 3 < count; i += 4)
100 __m128 vDst = _mm_loadu_ps(dst + i);
101 __m128 vSrc = _mm_loadu_ps(src + i);
103 #if defined(DSPARK_SIMD_FMA)
104 _mm_storeu_ps(dst + i, _mm_fmadd_ps(vSrc, vGain, vDst));
106 _mm_storeu_ps(dst + i, _mm_add_ps(vDst, _mm_mul_ps(vSrc, vGain)));
109 for (; i < count; ++i) dst[i] += src[i] * gain;
111#elif defined(DSPARK_SIMD_NEON)
112 const float32x4_t vGain = vdupq_n_f32(gain);
114 for (; i + 3 < count; i += 4)
116 float32x4_t vDst = vld1q_f32(dst + i);
117 float32x4_t vSrc = vld1q_f32(src + i);
120 vst1q_f32(dst + i, vfmaq_f32(vDst, vSrc, vGain));
122 for (; i < count; ++i) dst[i] += src[i] * gain;
125 for (
int i = 0; i < count; ++i) dst[i] += src[i] * gain;
130inline void addWithGain(
double* DSPARK_RESTRICT dst,
const double* DSPARK_RESTRICT src,
double gain,
int count)
noexcept
132#if defined(DSPARK_SIMD_AVX)
133 const __m256d vGain = _mm256_set1_pd(gain);
135 for (; i + 3 < count; i += 4)
137 __m256d vDst = _mm256_loadu_pd(dst + i);
138 __m256d vSrc = _mm256_loadu_pd(src + i);
140 #if defined(DSPARK_SIMD_FMA)
141 _mm256_storeu_pd(dst + i, _mm256_fmadd_pd(vSrc, vGain, vDst));
143 _mm256_storeu_pd(dst + i, _mm256_add_pd(vDst, _mm256_mul_pd(vSrc, vGain)));
146 for (; i < count; ++i) dst[i] += src[i] * gain;
148#elif defined(DSPARK_SIMD_SSE2)
149 const __m128d vGain = _mm_set1_pd(gain);
151 for (; i + 1 < count; i += 2)
153 __m128d vDst = _mm_loadu_pd(dst + i);
154 __m128d vSrc = _mm_loadu_pd(src + i);
156 #if defined(DSPARK_SIMD_FMA)
157 _mm_storeu_pd(dst + i, _mm_fmadd_pd(vSrc, vGain, vDst));
159 _mm_storeu_pd(dst + i, _mm_add_pd(vDst, _mm_mul_pd(vSrc, vGain)));
162 for (; i < count; ++i) dst[i] += src[i] * gain;
164#elif defined(DSPARK_SIMD_NEON)
165 const float64x2_t vGain = vdupq_n_f64(gain);
167 for (; i + 1 < count; i += 2)
169 float64x2_t vDst = vld1q_f64(dst + i);
170 float64x2_t vSrc = vld1q_f64(src + i);
171 vst1q_f64(dst + i, vfmaq_f64(vDst, vSrc, vGain));
173 for (; i < count; ++i) dst[i] += src[i] * gain;
175 for (
int i = 0; i < count; ++i) dst[i] += src[i] * gain;
186inline void applyGain(
float* DSPARK_RESTRICT data,
float gain,
int count)
noexcept
188#if defined(DSPARK_SIMD_AVX)
189 const __m256 vGain = _mm256_set1_ps(gain);
191 for (; i + 7 < count; i += 8)
193 __m256 v = _mm256_loadu_ps(data + i);
194 _mm256_storeu_ps(data + i, _mm256_mul_ps(v, vGain));
196 for (; i < count; ++i) data[i] *= gain;
198#elif defined(DSPARK_SIMD_SSE2)
199 const __m128 vGain = _mm_set1_ps(gain);
201 for (; i + 3 < count; i += 4)
203 __m128 v = _mm_loadu_ps(data + i);
204 _mm_storeu_ps(data + i, _mm_mul_ps(v, vGain));
206 for (; i < count; ++i) data[i] *= gain;
208#elif defined(DSPARK_SIMD_NEON)
209 const float32x4_t vGain = vdupq_n_f32(gain);
211 for (; i + 3 < count; i += 4)
213 float32x4_t v = vld1q_f32(data + i);
214 vst1q_f32(data + i, vmulq_f32(v, vGain));
216 for (; i < count; ++i) data[i] *= gain;
219 for (
int i = 0; i < count; ++i) data[i] *= gain;
224inline void applyGain(
double* DSPARK_RESTRICT data,
double gain,
int count)
noexcept
226#if defined(DSPARK_SIMD_AVX)
227 const __m256d vGain = _mm256_set1_pd(gain);
229 for (; i + 3 < count; i += 4)
230 _mm256_storeu_pd(data + i, _mm256_mul_pd(_mm256_loadu_pd(data + i), vGain));
231 for (; i < count; ++i) data[i] *= gain;
233#elif defined(DSPARK_SIMD_SSE2)
234 const __m128d vGain = _mm_set1_pd(gain);
236 for (; i + 1 < count; i += 2)
238 __m128d v = _mm_loadu_pd(data + i);
239 _mm_storeu_pd(data + i, _mm_mul_pd(v, vGain));
241 for (; i < count; ++i) data[i] *= gain;
243#elif defined(DSPARK_SIMD_NEON)
244 const float64x2_t vGain = vdupq_n_f64(gain);
246 for (; i + 1 < count; i += 2)
247 vst1q_f64(data + i, vmulq_f64(vld1q_f64(data + i), vGain));
248 for (; i < count; ++i) data[i] *= gain;
250 for (
int i = 0; i < count; ++i) data[i] *= gain;
264inline float peakLevel(
const float* DSPARK_RESTRICT data,
int count)
noexcept
266#if defined(DSPARK_SIMD_AVX)
267 const __m256 absMask = _mm256_castsi256_ps(_mm256_set1_epi32(0x7FFFFFFF));
268 __m256 vMax = _mm256_setzero_ps();
270 for (; i + 7 < count; i += 8)
272 __m256 v = _mm256_loadu_ps(data + i);
273 v = _mm256_and_ps(v, absMask);
277 vMax = _mm256_max_ps(v, vMax);
279 __m128 hi = _mm256_extractf128_ps(vMax, 1);
280 __m128 lo = _mm256_castps256_ps128(vMax);
281 __m128 m4 = _mm_max_ps(lo, hi);
282 __m128 m2 = _mm_max_ps(m4, _mm_movehl_ps(m4, m4));
283 __m128 m1 = _mm_max_ss(m2, _mm_shuffle_ps(m2, m2, 1));
284 float peak = _mm_cvtss_f32(m1);
286 for (; i < count; ++i)
288 float a = data[i] < 0.0f ? -data[i] : data[i];
289 if (a > peak) peak = a;
293#elif defined(DSPARK_SIMD_SSE2)
294 const __m128 absMask = _mm_castsi128_ps(_mm_set1_epi32(0x7FFFFFFF));
295 __m128 vMax = _mm_setzero_ps();
297 for (; i + 3 < count; i += 4)
299 __m128 v = _mm_loadu_ps(data + i);
300 v = _mm_and_ps(v, absMask);
301 vMax = _mm_max_ps(v, vMax);
303 __m128 shuf = _mm_movehl_ps(vMax, vMax);
304 __m128 maxPair = _mm_max_ps(vMax, shuf);
305 __m128 maxSingle = _mm_max_ss(maxPair, _mm_shuffle_ps(maxPair, maxPair, 1));
306 float peak = _mm_cvtss_f32(maxSingle);
308 for (; i < count; ++i)
310 float a = data[i] < 0.0f ? -data[i] : data[i];
311 if (a > peak) peak = a;
315#elif defined(DSPARK_SIMD_NEON)
316 float32x4_t vMax = vdupq_n_f32(0.0f);
318 for (; i + 3 < count; i += 4)
320 float32x4_t v = vld1q_f32(data + i);
322 vMax = vmaxnmq_f32(vMax, v);
324 float peak = vmaxvq_f32(vMax);
326 for (; i < count; ++i)
328 float a = data[i] < 0.0f ? -data[i] : data[i];
329 if (a > peak) peak = a;
335 for (
int i = 0; i < count; ++i)
337 float a = data[i] < 0.0f ? -data[i] : data[i];
338 if (a > peak) peak = a;
345inline double peakLevel(
const double* DSPARK_RESTRICT data,
int count)
noexcept
347#if defined(DSPARK_SIMD_AVX)
348 const __m256d absMask = _mm256_castsi256_pd(_mm256_set1_epi64x(0x7FFFFFFFFFFFFFFFll));
349 __m256d vMax = _mm256_setzero_pd();
351 for (; i + 3 < count; i += 4)
352 vMax = _mm256_max_pd(_mm256_and_pd(_mm256_loadu_pd(data + i), absMask), vMax);
353 __m128d lo = _mm256_castpd256_pd128(vMax);
354 __m128d hi = _mm256_extractf128_pd(vMax, 1);
355 __m128d m2 = _mm_max_pd(lo, hi);
356 double peak = _mm_cvtsd_f64(_mm_max_sd(m2, _mm_unpackhi_pd(m2, m2)));
358 for (; i < count; ++i)
360 double a = data[i] < 0.0 ? -data[i] : data[i];
361 if (a > peak) peak = a;
365#elif defined(DSPARK_SIMD_SSE2)
366 const __m128d absMask = _mm_castsi128_pd(_mm_set_epi64x(
367 static_cast<int64_t
>(0x7FFFFFFFFFFFFFFF),
368 static_cast<int64_t
>(0x7FFFFFFFFFFFFFFF)));
369 __m128d vMax = _mm_setzero_pd();
371 for (; i + 1 < count; i += 2)
373 __m128d v = _mm_loadu_pd(data + i);
374 v = _mm_and_pd(v, absMask);
375 vMax = _mm_max_pd(v, vMax);
377 __m128d hi = _mm_unpackhi_pd(vMax, vMax);
378 __m128d maxVal = _mm_max_sd(vMax, hi);
379 double peak = _mm_cvtsd_f64(maxVal);
381 for (; i < count; ++i)
383 double a = data[i] < 0.0 ? -data[i] : data[i];
384 if (a > peak) peak = a;
388#elif defined(DSPARK_SIMD_NEON)
389 float64x2_t vMax = vdupq_n_f64(0.0);
391 for (; i + 1 < count; i += 2)
392 vMax = vmaxnmq_f64(vMax, vabsq_f64(vld1q_f64(data + i)));
393 double peak = vmaxvq_f64(vMax);
395 for (; i < count; ++i)
397 double a = data[i] < 0.0 ? -data[i] : data[i];
398 if (a > peak) peak = a;
403 for (
int i = 0; i < count; ++i)
405 double a = data[i] < 0.0 ? -data[i] : data[i];
406 if (a > peak) peak = a;
419inline float dotProduct(
const float* DSPARK_RESTRICT a,
const float* DSPARK_RESTRICT b,
int count)
noexcept
421#if defined(DSPARK_SIMD_AVX)
424 __m256 vSum0 = _mm256_setzero_ps();
425 __m256 vSum1 = _mm256_setzero_ps();
426 __m256 vSum2 = _mm256_setzero_ps();
427 __m256 vSum3 = _mm256_setzero_ps();
429 for (; i + 31 < count; i += 32)
431 #if defined(DSPARK_SIMD_FMA)
432 vSum0 = _mm256_fmadd_ps(_mm256_loadu_ps(a + i), _mm256_loadu_ps(b + i), vSum0);
433 vSum1 = _mm256_fmadd_ps(_mm256_loadu_ps(a + i + 8), _mm256_loadu_ps(b + i + 8), vSum1);
434 vSum2 = _mm256_fmadd_ps(_mm256_loadu_ps(a + i + 16), _mm256_loadu_ps(b + i + 16), vSum2);
435 vSum3 = _mm256_fmadd_ps(_mm256_loadu_ps(a + i + 24), _mm256_loadu_ps(b + i + 24), vSum3);
437 vSum0 = _mm256_add_ps(vSum0, _mm256_mul_ps(_mm256_loadu_ps(a + i), _mm256_loadu_ps(b + i)));
438 vSum1 = _mm256_add_ps(vSum1, _mm256_mul_ps(_mm256_loadu_ps(a + i + 8), _mm256_loadu_ps(b + i + 8)));
439 vSum2 = _mm256_add_ps(vSum2, _mm256_mul_ps(_mm256_loadu_ps(a + i + 16), _mm256_loadu_ps(b + i + 16)));
440 vSum3 = _mm256_add_ps(vSum3, _mm256_mul_ps(_mm256_loadu_ps(a + i + 24), _mm256_loadu_ps(b + i + 24)));
443 for (; i + 7 < count; i += 8)
445 #if defined(DSPARK_SIMD_FMA)
446 vSum0 = _mm256_fmadd_ps(_mm256_loadu_ps(a + i), _mm256_loadu_ps(b + i), vSum0);
448 vSum0 = _mm256_add_ps(vSum0, _mm256_mul_ps(_mm256_loadu_ps(a + i), _mm256_loadu_ps(b + i)));
451 __m256 vSum = _mm256_add_ps(_mm256_add_ps(vSum0, vSum1), _mm256_add_ps(vSum2, vSum3));
452 __m128 hi = _mm256_extractf128_ps(vSum, 1);
453 __m128 lo = _mm256_castps256_ps128(vSum);
454 __m128 sum4 = _mm_add_ps(lo, hi);
455 __m128 shuf = _mm_movehl_ps(sum4, sum4);
456 __m128 sum2 = _mm_add_ps(sum4, shuf);
457 __m128 sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
458 float sum = _mm_cvtss_f32(sum1);
460 for (; i < count; ++i) sum += a[i] * b[i];
463#elif defined(DSPARK_SIMD_SSE2)
465 __m128 vSum0 = _mm_setzero_ps();
466 __m128 vSum1 = _mm_setzero_ps();
468 for (; i + 7 < count; i += 8)
470 #if defined(DSPARK_SIMD_FMA)
471 vSum0 = _mm_fmadd_ps(_mm_loadu_ps(a + i), _mm_loadu_ps(b + i), vSum0);
472 vSum1 = _mm_fmadd_ps(_mm_loadu_ps(a + i + 4), _mm_loadu_ps(b + i + 4), vSum1);
474 vSum0 = _mm_add_ps(vSum0, _mm_mul_ps(_mm_loadu_ps(a + i), _mm_loadu_ps(b + i)));
475 vSum1 = _mm_add_ps(vSum1, _mm_mul_ps(_mm_loadu_ps(a + i + 4), _mm_loadu_ps(b + i + 4)));
478 for (; i + 3 < count; i += 4)
480 #if defined(DSPARK_SIMD_FMA)
481 vSum0 = _mm_fmadd_ps(_mm_loadu_ps(a + i), _mm_loadu_ps(b + i), vSum0);
483 vSum0 = _mm_add_ps(vSum0, _mm_mul_ps(_mm_loadu_ps(a + i), _mm_loadu_ps(b + i)));
486 alignas(16)
float tmp[4];
487 _mm_store_ps(tmp, _mm_add_ps(vSum0, vSum1));
488 float sum = tmp[0] + tmp[1] + tmp[2] + tmp[3];
490 for (; i < count; ++i) sum += a[i] * b[i];
493#elif defined(DSPARK_SIMD_NEON)
494 float32x4_t vSum0 = vdupq_n_f32(0.0f);
495 float32x4_t vSum1 = vdupq_n_f32(0.0f);
497 for (; i + 7 < count; i += 8)
499 vSum0 = vfmaq_f32(vSum0, vld1q_f32(a + i), vld1q_f32(b + i));
500 vSum1 = vfmaq_f32(vSum1, vld1q_f32(a + i + 4), vld1q_f32(b + i + 4));
502 for (; i + 3 < count; i += 4)
503 vSum0 = vfmaq_f32(vSum0, vld1q_f32(a + i), vld1q_f32(b + i));
504 float sum = vaddvq_f32(vaddq_f32(vSum0, vSum1));
506 for (; i < count; ++i) sum += a[i] * b[i];
511 for (
int i = 0; i < count; ++i) sum += a[i] * b[i];
517inline double dotProduct(
const double* DSPARK_RESTRICT a,
const double* DSPARK_RESTRICT b,
int count)
noexcept
519#if defined(DSPARK_SIMD_AVX)
520 __m256d vSum0 = _mm256_setzero_pd();
521 __m256d vSum1 = _mm256_setzero_pd();
523 for (; i + 7 < count; i += 8)
525 #if defined(DSPARK_SIMD_FMA)
526 vSum0 = _mm256_fmadd_pd(_mm256_loadu_pd(a + i), _mm256_loadu_pd(b + i), vSum0);
527 vSum1 = _mm256_fmadd_pd(_mm256_loadu_pd(a + i + 4), _mm256_loadu_pd(b + i + 4), vSum1);
529 vSum0 = _mm256_add_pd(vSum0, _mm256_mul_pd(_mm256_loadu_pd(a + i), _mm256_loadu_pd(b + i)));
530 vSum1 = _mm256_add_pd(vSum1, _mm256_mul_pd(_mm256_loadu_pd(a + i + 4), _mm256_loadu_pd(b + i + 4)));
533 for (; i + 3 < count; i += 4)
535 #if defined(DSPARK_SIMD_FMA)
536 vSum0 = _mm256_fmadd_pd(_mm256_loadu_pd(a + i), _mm256_loadu_pd(b + i), vSum0);
538 vSum0 = _mm256_add_pd(vSum0, _mm256_mul_pd(_mm256_loadu_pd(a + i), _mm256_loadu_pd(b + i)));
541 __m256d vSum = _mm256_add_pd(vSum0, vSum1);
542 __m128d lo = _mm256_castpd256_pd128(vSum);
543 __m128d hi = _mm256_extractf128_pd(vSum, 1);
544 __m128d s2 = _mm_add_pd(lo, hi);
545 double sum = _mm_cvtsd_f64(_mm_add_sd(s2, _mm_unpackhi_pd(s2, s2)));
547 for (; i < count; ++i) sum += a[i] * b[i];
550#elif defined(DSPARK_SIMD_SSE2)
551 __m128d vSum0 = _mm_setzero_pd();
552 __m128d vSum1 = _mm_setzero_pd();
554 for (; i + 3 < count; i += 4)
556 #if defined(DSPARK_SIMD_FMA)
557 vSum0 = _mm_fmadd_pd(_mm_loadu_pd(a + i), _mm_loadu_pd(b + i), vSum0);
558 vSum1 = _mm_fmadd_pd(_mm_loadu_pd(a + i + 2), _mm_loadu_pd(b + i + 2), vSum1);
560 vSum0 = _mm_add_pd(vSum0, _mm_mul_pd(_mm_loadu_pd(a + i), _mm_loadu_pd(b + i)));
561 vSum1 = _mm_add_pd(vSum1, _mm_mul_pd(_mm_loadu_pd(a + i + 2), _mm_loadu_pd(b + i + 2)));
564 for (; i + 1 < count; i += 2)
566 #if defined(DSPARK_SIMD_FMA)
567 vSum0 = _mm_fmadd_pd(_mm_loadu_pd(a + i), _mm_loadu_pd(b + i), vSum0);
569 vSum0 = _mm_add_pd(vSum0, _mm_mul_pd(_mm_loadu_pd(a + i), _mm_loadu_pd(b + i)));
572 __m128d vSum = _mm_add_pd(vSum0, vSum1);
573 __m128d hi = _mm_unpackhi_pd(vSum, vSum);
574 double sum = _mm_cvtsd_f64(_mm_add_sd(vSum, hi));
576 for (; i < count; ++i) sum += a[i] * b[i];
579#elif defined(DSPARK_SIMD_NEON)
580 float64x2_t vSum0 = vdupq_n_f64(0.0);
581 float64x2_t vSum1 = vdupq_n_f64(0.0);
583 for (; i + 3 < count; i += 4)
585 vSum0 = vfmaq_f64(vSum0, vld1q_f64(a + i), vld1q_f64(b + i));
586 vSum1 = vfmaq_f64(vSum1, vld1q_f64(a + i + 2), vld1q_f64(b + i + 2));
588 for (; i + 1 < count; i += 2)
589 vSum0 = vfmaq_f64(vSum0, vld1q_f64(a + i), vld1q_f64(b + i));
590 double sum = vaddvq_f64(vaddq_f64(vSum0, vSum1));
592 for (; i < count; ++i) sum += a[i] * b[i];
596 for (
int i = 0; i < count; ++i) sum += a[i] * b[i];
608inline void add(
float* DSPARK_RESTRICT dst,
const float* DSPARK_RESTRICT src,
int count)
noexcept
610#if defined(DSPARK_SIMD_AVX)
612 for (; i + 7 < count; i += 8)
614 __m256 vDst = _mm256_loadu_ps(dst + i);
615 __m256 vSrc = _mm256_loadu_ps(src + i);
616 _mm256_storeu_ps(dst + i, _mm256_add_ps(vDst, vSrc));
618 for (; i < count; ++i) dst[i] += src[i];
620#elif defined(DSPARK_SIMD_SSE2)
622 for (; i + 3 < count; i += 4)
624 __m128 vDst = _mm_loadu_ps(dst + i);
625 __m128 vSrc = _mm_loadu_ps(src + i);
626 _mm_storeu_ps(dst + i, _mm_add_ps(vDst, vSrc));
628 for (; i < count; ++i) dst[i] += src[i];
630#elif defined(DSPARK_SIMD_NEON)
632 for (; i + 3 < count; i += 4)
634 float32x4_t vDst = vld1q_f32(dst + i);
635 float32x4_t vSrc = vld1q_f32(src + i);
636 vst1q_f32(dst + i, vaddq_f32(vDst, vSrc));
638 for (; i < count; ++i) dst[i] += src[i];
641 for (
int i = 0; i < count; ++i) dst[i] += src[i];
646inline void add(
double* DSPARK_RESTRICT dst,
const double* DSPARK_RESTRICT src,
int count)
noexcept
648#if defined(DSPARK_SIMD_AVX)
650 for (; i + 3 < count; i += 4)
651 _mm256_storeu_pd(dst + i, _mm256_add_pd(_mm256_loadu_pd(dst + i), _mm256_loadu_pd(src + i)));
652 for (; i < count; ++i) dst[i] += src[i];
654#elif defined(DSPARK_SIMD_SSE2)
656 for (; i + 1 < count; i += 2)
658 __m128d vDst = _mm_loadu_pd(dst + i);
659 __m128d vSrc = _mm_loadu_pd(src + i);
660 _mm_storeu_pd(dst + i, _mm_add_pd(vDst, vSrc));
662 for (; i < count; ++i) dst[i] += src[i];
664#elif defined(DSPARK_SIMD_NEON)
666 for (; i + 1 < count; i += 2)
667 vst1q_f64(dst + i, vaddq_f64(vld1q_f64(dst + i), vld1q_f64(src + i)));
668 for (; i < count; ++i) dst[i] += src[i];
670 for (
int i = 0; i < count; ++i) dst[i] += src[i];
679inline void multiply(
float* DSPARK_RESTRICT dst,
const float* DSPARK_RESTRICT a,
const float* DSPARK_RESTRICT b,
int count)
noexcept
681#if defined(DSPARK_SIMD_AVX)
683 for (; i + 7 < count; i += 8)
684 _mm256_storeu_ps(dst + i, _mm256_mul_ps(_mm256_loadu_ps(a + i), _mm256_loadu_ps(b + i)));
685 for (; i < count; ++i) dst[i] = a[i] * b[i];
686#elif defined(DSPARK_SIMD_SSE2)
688 for (; i + 3 < count; i += 4)
689 _mm_storeu_ps(dst + i, _mm_mul_ps(_mm_loadu_ps(a + i), _mm_loadu_ps(b + i)));
690 for (; i < count; ++i) dst[i] = a[i] * b[i];
691#elif defined(DSPARK_SIMD_NEON)
693 for (; i + 3 < count; i += 4)
694 vst1q_f32(dst + i, vmulq_f32(vld1q_f32(a + i), vld1q_f32(b + i)));
695 for (; i < count; ++i) dst[i] = a[i] * b[i];
697 for (
int i = 0; i < count; ++i) dst[i] = a[i] * b[i];
702inline void multiply(
double* DSPARK_RESTRICT dst,
const double* DSPARK_RESTRICT a,
const double* DSPARK_RESTRICT b,
int count)
noexcept
704#if defined(DSPARK_SIMD_AVX)
706 for (; i + 3 < count; i += 4)
707 _mm256_storeu_pd(dst + i, _mm256_mul_pd(_mm256_loadu_pd(a + i), _mm256_loadu_pd(b + i)));
708 for (; i < count; ++i) dst[i] = a[i] * b[i];
709#elif defined(DSPARK_SIMD_SSE2)
711 for (; i + 1 < count; i += 2)
712 _mm_storeu_pd(dst + i, _mm_mul_pd(_mm_loadu_pd(a + i), _mm_loadu_pd(b + i)));
713 for (; i < count; ++i) dst[i] = a[i] * b[i];
715#elif defined(DSPARK_SIMD_NEON)
717 for (; i + 1 < count; i += 2)
718 vst1q_f64(dst + i, vmulq_f64(vld1q_f64(a + i), vld1q_f64(b + i)));
719 for (; i < count; ++i) dst[i] = a[i] * b[i];
721 for (
int i = 0; i < count; ++i) dst[i] = a[i] * b[i];
730inline void copyWithGain(
float* DSPARK_RESTRICT dst,
const float* DSPARK_RESTRICT src,
float gain,
int count)
noexcept
732#if defined(DSPARK_SIMD_AVX)
733 const __m256 vGain = _mm256_set1_ps(gain);
735 for (; i + 7 < count; i += 8)
736 _mm256_storeu_ps(dst + i, _mm256_mul_ps(_mm256_loadu_ps(src + i), vGain));
737 for (; i < count; ++i) dst[i] = src[i] * gain;
738#elif defined(DSPARK_SIMD_SSE2)
739 const __m128 vGain = _mm_set1_ps(gain);
741 for (; i + 3 < count; i += 4)
742 _mm_storeu_ps(dst + i, _mm_mul_ps(_mm_loadu_ps(src + i), vGain));
743 for (; i < count; ++i) dst[i] = src[i] * gain;
744#elif defined(DSPARK_SIMD_NEON)
745 const float32x4_t vGain = vdupq_n_f32(gain);
747 for (; i + 3 < count; i += 4)
748 vst1q_f32(dst + i, vmulq_f32(vld1q_f32(src + i), vGain));
749 for (; i < count; ++i) dst[i] = src[i] * gain;
751 for (
int i = 0; i < count; ++i) dst[i] = src[i] * gain;
756inline void copyWithGain(
double* DSPARK_RESTRICT dst,
const double* DSPARK_RESTRICT src,
double gain,
int count)
noexcept
758#if defined(DSPARK_SIMD_AVX)
759 const __m256d vGain = _mm256_set1_pd(gain);
761 for (; i + 3 < count; i += 4)
762 _mm256_storeu_pd(dst + i, _mm256_mul_pd(_mm256_loadu_pd(src + i), vGain));
763 for (; i < count; ++i) dst[i] = src[i] * gain;
764#elif defined(DSPARK_SIMD_SSE2)
765 const __m128d vGain = _mm_set1_pd(gain);
767 for (; i + 1 < count; i += 2)
768 _mm_storeu_pd(dst + i, _mm_mul_pd(_mm_loadu_pd(src + i), vGain));
769 for (; i < count; ++i) dst[i] = src[i] * gain;
771#elif defined(DSPARK_SIMD_NEON)
772 const float64x2_t vGain = vdupq_n_f64(gain);
774 for (; i + 1 < count; i += 2)
775 vst1q_f64(dst + i, vmulq_f64(vld1q_f64(src + i), vGain));
776 for (; i < count; ++i) dst[i] = src[i] * gain;
778 for (
int i = 0; i < count; ++i) dst[i] = src[i] * gain;
794inline void applyGainRamp(
float* DSPARK_RESTRICT data,
float gainStart,
float gainEnd,
int count)
noexcept
796 if (count <= 0)
return;
797 const float step = (gainEnd - gainStart) /
static_cast<float>(count);
798#if defined(DSPARK_SIMD_AVX)
799 const __m256 vStep = _mm256_set1_ps(step * 8.0f);
800 __m256 vGain = _mm256_setr_ps(gainStart, gainStart + step,
801 gainStart + 2 * step, gainStart + 3 * step,
802 gainStart + 4 * step, gainStart + 5 * step,
803 gainStart + 6 * step, gainStart + 7 * step);
805 for (; i + 7 < count; i += 8)
807 _mm256_storeu_ps(data + i, _mm256_mul_ps(_mm256_loadu_ps(data + i), vGain));
808 vGain = _mm256_add_ps(vGain, vStep);
810 for (; i < count; ++i) data[i] *= gainStart + step * static_cast<float>(i);
812#elif defined(DSPARK_SIMD_SSE2)
813 const __m128 vStep = _mm_set1_ps(step * 4.0f);
814 __m128 vGain = _mm_setr_ps(gainStart, gainStart + step, gainStart + 2 * step, gainStart + 3 * step);
816 for (; i + 3 < count; i += 4)
818 _mm_storeu_ps(data + i, _mm_mul_ps(_mm_loadu_ps(data + i), vGain));
819 vGain = _mm_add_ps(vGain, vStep);
821 for (; i < count; ++i) data[i] *= gainStart + step * static_cast<float>(i);
823#elif defined(DSPARK_SIMD_NEON)
824 const float32x4_t vStep = vdupq_n_f32(step * 4.0f);
825 const float init[4] = { gainStart, gainStart + step, gainStart + 2 * step, gainStart + 3 * step };
826 float32x4_t vGain = vld1q_f32(init);
828 for (; i + 3 < count; i += 4)
830 vst1q_f32(data + i, vmulq_f32(vld1q_f32(data + i), vGain));
831 vGain = vaddq_f32(vGain, vStep);
833 for (; i < count; ++i) data[i] *= gainStart + step * static_cast<float>(i);
836 for (
int i = 0; i < count; ++i) data[i] *= gainStart + step * static_cast<float>(i);
841inline void applyGainRamp(
double* DSPARK_RESTRICT data,
double gainStart,
double gainEnd,
int count)
noexcept
843 if (count <= 0)
return;
844 const double step = (gainEnd - gainStart) /
static_cast<double>(count);
845#if defined(DSPARK_SIMD_AVX)
846 const __m256d vStep = _mm256_set1_pd(step * 4.0);
847 __m256d vGain = _mm256_setr_pd(gainStart, gainStart + step,
848 gainStart + 2 * step, gainStart + 3 * step);
850 for (; i + 3 < count; i += 4)
852 _mm256_storeu_pd(data + i, _mm256_mul_pd(_mm256_loadu_pd(data + i), vGain));
853 vGain = _mm256_add_pd(vGain, vStep);
855 for (; i < count; ++i) data[i] *= gainStart + step * static_cast<double>(i);
857#elif defined(DSPARK_SIMD_SSE2)
858 const __m128d vStep = _mm_set1_pd(step * 2.0);
859 __m128d vGain = _mm_setr_pd(gainStart, gainStart + step);
861 for (; i + 1 < count; i += 2)
863 _mm_storeu_pd(data + i, _mm_mul_pd(_mm_loadu_pd(data + i), vGain));
864 vGain = _mm_add_pd(vGain, vStep);
866 for (; i < count; ++i) data[i] *= gainStart + step * static_cast<double>(i);
868#elif defined(DSPARK_SIMD_NEON)
869 const float64x2_t vStep = vdupq_n_f64(step * 2.0);
870 const double init[2] = { gainStart, gainStart + step };
871 float64x2_t vGain = vld1q_f64(init);
873 for (; i + 1 < count; i += 2)
875 vst1q_f64(data + i, vmulq_f64(vld1q_f64(data + i), vGain));
876 vGain = vaddq_f64(vGain, vStep);
878 for (; i < count; ++i) data[i] *= gainStart + step * static_cast<double>(i);
881 for (
int i = 0; i < count; ++i) data[i] *= gainStart + step * static_cast<double>(i);
896inline void addWithGainRamp(
float* DSPARK_RESTRICT dst,
const float* DSPARK_RESTRICT src,
897 float gainStart,
float gainEnd,
int count)
noexcept
899 if (count <= 0)
return;
900 const float step = (gainEnd - gainStart) /
static_cast<float>(count);
901#if defined(DSPARK_SIMD_AVX)
902 const __m256 vStep = _mm256_set1_ps(step * 8.0f);
903 __m256 vGain = _mm256_setr_ps(gainStart, gainStart + step,
904 gainStart + 2 * step, gainStart + 3 * step,
905 gainStart + 4 * step, gainStart + 5 * step,
906 gainStart + 6 * step, gainStart + 7 * step);
908 for (; i + 7 < count; i += 8)
910 const __m256 vDst = _mm256_loadu_ps(dst + i);
911 const __m256 vSrc = _mm256_loadu_ps(src + i);
912 #if defined(DSPARK_SIMD_FMA)
913 _mm256_storeu_ps(dst + i, _mm256_fmadd_ps(vSrc, vGain, vDst));
915 _mm256_storeu_ps(dst + i, _mm256_add_ps(vDst, _mm256_mul_ps(vSrc, vGain)));
917 vGain = _mm256_add_ps(vGain, vStep);
919 for (; i < count; ++i) dst[i] += src[i] * (gainStart + step * static_cast<float>(i));
921#elif defined(DSPARK_SIMD_SSE2)
922 const __m128 vStep = _mm_set1_ps(step * 4.0f);
923 __m128 vGain = _mm_setr_ps(gainStart, gainStart + step, gainStart + 2 * step, gainStart + 3 * step);
925 for (; i + 3 < count; i += 4)
927 const __m128 vDst = _mm_loadu_ps(dst + i);
928 const __m128 vSrc = _mm_loadu_ps(src + i);
929 #if defined(DSPARK_SIMD_FMA)
930 _mm_storeu_ps(dst + i, _mm_fmadd_ps(vSrc, vGain, vDst));
932 _mm_storeu_ps(dst + i, _mm_add_ps(vDst, _mm_mul_ps(vSrc, vGain)));
934 vGain = _mm_add_ps(vGain, vStep);
936 for (; i < count; ++i) dst[i] += src[i] * (gainStart + step * static_cast<float>(i));
938#elif defined(DSPARK_SIMD_NEON)
939 const float32x4_t vStep = vdupq_n_f32(step * 4.0f);
940 const float init[4] = { gainStart, gainStart + step, gainStart + 2 * step, gainStart + 3 * step };
941 float32x4_t vGain = vld1q_f32(init);
943 for (; i + 3 < count; i += 4)
945 vst1q_f32(dst + i, vfmaq_f32(vld1q_f32(dst + i), vld1q_f32(src + i), vGain));
946 vGain = vaddq_f32(vGain, vStep);
948 for (; i < count; ++i) dst[i] += src[i] * (gainStart + step * static_cast<float>(i));
951 for (
int i = 0; i < count; ++i) dst[i] += src[i] * (gainStart + step * static_cast<float>(i));
956inline void addWithGainRamp(
double* DSPARK_RESTRICT dst,
const double* DSPARK_RESTRICT src,
957 double gainStart,
double gainEnd,
int count)
noexcept
959 if (count <= 0)
return;
960 const double step = (gainEnd - gainStart) /
static_cast<double>(count);
961#if defined(DSPARK_SIMD_AVX)
962 const __m256d vStep = _mm256_set1_pd(step * 4.0);
963 __m256d vGain = _mm256_setr_pd(gainStart, gainStart + step,
964 gainStart + 2 * step, gainStart + 3 * step);
966 for (; i + 3 < count; i += 4)
968 const __m256d vDst = _mm256_loadu_pd(dst + i);
969 const __m256d vSrc = _mm256_loadu_pd(src + i);
970 #if defined(DSPARK_SIMD_FMA)
971 _mm256_storeu_pd(dst + i, _mm256_fmadd_pd(vSrc, vGain, vDst));
973 _mm256_storeu_pd(dst + i, _mm256_add_pd(vDst, _mm256_mul_pd(vSrc, vGain)));
975 vGain = _mm256_add_pd(vGain, vStep);
977 for (; i < count; ++i) dst[i] += src[i] * (gainStart + step * static_cast<double>(i));
979#elif defined(DSPARK_SIMD_SSE2)
980 const __m128d vStep = _mm_set1_pd(step * 2.0);
981 __m128d vGain = _mm_setr_pd(gainStart, gainStart + step);
983 for (; i + 1 < count; i += 2)
985 const __m128d vDst = _mm_loadu_pd(dst + i);
986 const __m128d vSrc = _mm_loadu_pd(src + i);
987 #if defined(DSPARK_SIMD_FMA)
988 _mm_storeu_pd(dst + i, _mm_fmadd_pd(vSrc, vGain, vDst));
990 _mm_storeu_pd(dst + i, _mm_add_pd(vDst, _mm_mul_pd(vSrc, vGain)));
992 vGain = _mm_add_pd(vGain, vStep);
994 for (; i < count; ++i) dst[i] += src[i] * (gainStart + step * static_cast<double>(i));
996#elif defined(DSPARK_SIMD_NEON)
997 const float64x2_t vStep = vdupq_n_f64(step * 2.0);
998 const double init[2] = { gainStart, gainStart + step };
999 float64x2_t vGain = vld1q_f64(init);
1001 for (; i + 1 < count; i += 2)
1003 vst1q_f64(dst + i, vfmaq_f64(vld1q_f64(dst + i), vld1q_f64(src + i), vGain));
1004 vGain = vaddq_f64(vGain, vStep);
1006 for (; i < count; ++i) dst[i] += src[i] * (gainStart + step * static_cast<double>(i));
1009 for (
int i = 0; i < count; ++i) dst[i] += src[i] * (gainStart + step * static_cast<double>(i));
1018inline float sumOfSquares(
const float* DSPARK_RESTRICT data,
int count)
noexcept
1024inline double sumOfSquares(
const double* DSPARK_RESTRICT data,
int count)
noexcept
1040 const float* DSPARK_RESTRICT b,
int bins)
noexcept
1042#if defined(DSPARK_SIMD_AVX)
1048 for (; k + 3 < bins; k += 4)
1050 const __m256 va = _mm256_loadu_ps(a + 2 * k);
1051 const __m256 vb = _mm256_loadu_ps(b + 2 * k);
1052 const __m256 vacc = _mm256_loadu_ps(accum + 2 * k);
1054 const __m256 aRe = _mm256_permute_ps(va, _MM_SHUFFLE(2, 2, 0, 0));
1055 const __m256 aIm = _mm256_permute_ps(va, _MM_SHUFFLE(3, 3, 1, 1));
1056 const __m256 bSwap = _mm256_permute_ps(vb, _MM_SHUFFLE(2, 3, 0, 1));
1058 #if defined(DSPARK_SIMD_FMA)
1059 const __m256 prod = _mm256_fmaddsub_ps(aRe, vb, _mm256_mul_ps(aIm, bSwap));
1061 const __m256 prod = _mm256_addsub_ps(_mm256_mul_ps(aRe, vb), _mm256_mul_ps(aIm, bSwap));
1064 _mm256_storeu_ps(accum + 2 * k, _mm256_add_ps(vacc, prod));
1066 for (; k < bins; ++k)
1068 const float re1 = a[2 * k], im1 = a[2 * k + 1];
1069 const float re2 = b[2 * k], im2 = b[2 * k + 1];
1070 accum[2 * k] += re1 * re2 - im1 * im2;
1071 accum[2 * k + 1] += re1 * im2 + im1 * re2;
1073#elif defined(DSPARK_SIMD_SSE2)
1075 const __m128 negMask = _mm_castsi128_ps(_mm_setr_epi32(
1076 static_cast<int>(0x80000000u), 0,
1077 static_cast<int>(0x80000000u), 0));
1080 for (; k + 1 < bins; k += 2)
1082 const __m128 va = _mm_loadu_ps(a + 2 * k);
1083 const __m128 vb = _mm_loadu_ps(b + 2 * k);
1084 __m128 vacc = _mm_loadu_ps(accum + 2 * k);
1086 const __m128 aRe = _mm_shuffle_ps(va, va, _MM_SHUFFLE(2, 2, 0, 0));
1087 const __m128 aIm = _mm_shuffle_ps(va, va, _MM_SHUFFLE(3, 3, 1, 1));
1088 const __m128 bSwap = _mm_shuffle_ps(vb, vb, _MM_SHUFFLE(2, 3, 0, 1));
1090 const __m128 p1 = _mm_mul_ps(aRe, vb);
1091 const __m128 p2 = _mm_xor_ps(_mm_mul_ps(aIm, bSwap), negMask);
1093 vacc = _mm_add_ps(vacc, _mm_add_ps(p1, p2));
1094 _mm_storeu_ps(accum + 2 * k, vacc);
1096 for (; k < bins; ++k)
1098 const float re1 = a[2 * k], im1 = a[2 * k + 1];
1099 const float re2 = b[2 * k], im2 = b[2 * k + 1];
1100 accum[2 * k] += re1 * re2 - im1 * im2;
1101 accum[2 * k + 1] += re1 * im2 + im1 * re2;
1103#elif defined(DSPARK_SIMD_NEON)
1104 alignas(16)
static constexpr uint32_t kNegRe[4] = { 0x80000000u, 0u, 0x80000000u, 0u };
1105 const uint32x4_t negMask = vld1q_u32(kNegRe);
1108 for (; k + 1 < bins; k += 2)
1110 const float32x4_t va = vld1q_f32(a + 2 * k);
1111 const float32x4_t vb = vld1q_f32(b + 2 * k);
1112 float32x4_t vacc = vld1q_f32(accum + 2 * k);
1114 const float32x4_t aRe = vtrn1q_f32(va, va);
1115 const float32x4_t aIm = vtrn2q_f32(va, va);
1116 const float32x4_t bSwap = vrev64q_f32(vb);
1118 const float32x4_t p1 = vmulq_f32(aRe, vb);
1119 const float32x4_t p2 = vreinterpretq_f32_u32(
1120 veorq_u32(vreinterpretq_u32_f32(vmulq_f32(aIm, bSwap)), negMask));
1122 vacc = vaddq_f32(vacc, vaddq_f32(p1, p2));
1123 vst1q_f32(accum + 2 * k, vacc);
1125 for (; k < bins; ++k)
1127 const float re1 = a[2 * k], im1 = a[2 * k + 1];
1128 const float re2 = b[2 * k], im2 = b[2 * k + 1];
1129 accum[2 * k] += re1 * re2 - im1 * im2;
1130 accum[2 * k + 1] += re1 * im2 + im1 * re2;
1133 for (
int k = 0; k < bins; ++k)
1135 const float re1 = a[2 * k], im1 = a[2 * k + 1];
1136 const float re2 = b[2 * k], im2 = b[2 * k + 1];
1137 accum[2 * k] += re1 * re2 - im1 * im2;
1138 accum[2 * k + 1] += re1 * im2 + im1 * re2;
1144inline void complexMulAccum(
double* DSPARK_RESTRICT accum,
const double* DSPARK_RESTRICT a,
1145 const double* DSPARK_RESTRICT b,
int bins)
noexcept
1147 for (
int k = 0; k < bins; ++k)
1149 const double re1 = a[2 * k], im1 = a[2 * k + 1];
1150 const double re2 = b[2 * k], im2 = b[2 * k + 1];
1151 accum[2 * k] += re1 * re2 - im1 * im2;
1152 accum[2 * k + 1] += re1 * im2 + im1 * re2;
1160template <
typename T>
1161void addWithGainT(T* DSPARK_RESTRICT dst,
const T* DSPARK_RESTRICT src, T gain,
int count)
noexcept
1163 static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>,
"SimdOps: only float and double are supported");
1167template <
typename T>
1168void applyGainT(T* DSPARK_RESTRICT data, T gain,
int count)
noexcept
1170 static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>,
"SimdOps: only float and double are supported");
1174template <
typename T>
1177 static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>,
"SimdOps: only float and double are supported");
1181template <
typename T>
1182T
dotProductT(
const T* DSPARK_RESTRICT a,
const T* DSPARK_RESTRICT b,
int count)
noexcept
1184 static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>,
"SimdOps: only float and double are supported");
1188template <
typename T>
1189void addT(T* DSPARK_RESTRICT dst,
const T* DSPARK_RESTRICT src,
int count)
noexcept
1191 static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>,
"SimdOps: only float and double are supported");
1192 add(dst, src, count);
1195template <
typename T>
1196void multiplyT(T* DSPARK_RESTRICT dst,
const T* DSPARK_RESTRICT a,
const T* DSPARK_RESTRICT b,
int count)
noexcept
1198 static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>,
"SimdOps: only float and double are supported");
1202template <
typename T>
1203void copyWithGainT(T* DSPARK_RESTRICT dst,
const T* DSPARK_RESTRICT src, T gain,
int count)
noexcept
1205 static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>,
"SimdOps: only float and double are supported");
1209template <
typename T>
1212 static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>,
"SimdOps: only float and double are supported");
1216template <
typename T>
1217void applyGainRampT(T* DSPARK_RESTRICT data, T gainStart, T gainEnd,
int count)
noexcept
1219 static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>,
"SimdOps: only float and double are supported");
1223template <
typename T>
1224void addWithGainRampT(T* DSPARK_RESTRICT dst,
const T* DSPARK_RESTRICT src, T gainStart, T gainEnd,
int count)
noexcept
1226 static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>,
"SimdOps: only float and double are supported");
1237template <
typename T,
int W>
struct Vec;
1239template <
typename T>
1243 static V load(
const T* p)
noexcept {
return *p; }
1244 static void store(T* p,
V v)
noexcept { *p = v; }
1245 static V set1(T x)
noexcept {
return x; }
1246 static V add(
V a,
V b)
noexcept {
return a + b; }
1247 static V sub(
V a,
V b)
noexcept {
return a - b; }
1248 static V mul(
V a,
V b)
noexcept {
return a * b; }
1249 static V mulSub(
V a,
V b,
V c,
V d)
noexcept {
return a * b - c * d; }
1250 static V mulAdd(
V a,
V b,
V c,
V d)
noexcept {
return a * b + c * d; }
1251 static V madd(
V a,
V b,
V c)
noexcept {
return a * b + c; }
1257 p[0] = a; p[1] = b; p[2] = c; p[3] = d;
1261#if defined(DSPARK_SIMD_SSE2)
1269 static V load(
const float* p)
noexcept {
return _mm_loadu_ps(p); }
1270 static void store(
float* p, V v)
noexcept { _mm_storeu_ps(p, v); }
1271 static V set1(
float x)
noexcept {
return _mm_set1_ps(x); }
1272 static V
add(V a, V b)
noexcept {
return _mm_add_ps(a, b); }
1273 static V sub(V a, V b)
noexcept {
return _mm_sub_ps(a, b); }
1274 static V mul(V a, V b)
noexcept {
return _mm_mul_ps(a, b); }
1275#if defined(DSPARK_SIMD_FMA)
1276 static V mulSub(V a, V b, V c, V d)
noexcept {
return _mm_fmsub_ps(a, b, _mm_mul_ps(c, d)); }
1277 static V mulAdd(V a, V b, V c, V d)
noexcept {
return _mm_fmadd_ps(a, b, _mm_mul_ps(c, d)); }
1278 static V madd(V a, V b, V c)
noexcept {
return _mm_fmadd_ps(a, b, c); }
1280 static V mulSub(V a, V b, V c, V d)
noexcept {
return _mm_sub_ps(_mm_mul_ps(a, b), _mm_mul_ps(c, d)); }
1281 static V mulAdd(V a, V b, V c, V d)
noexcept {
return _mm_add_ps(_mm_mul_ps(a, b), _mm_mul_ps(c, d)); }
1282 static V madd(V a, V b, V c)
noexcept {
return _mm_add_ps(_mm_mul_ps(a, b), c); }
1284 static V reverse(V v)
noexcept {
return _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 1, 2, 3)); }
1285 static void loadDeinterleave(
const float* p, V& re, V& im)
noexcept
1287 const V a = _mm_loadu_ps(p), b = _mm_loadu_ps(p + 4);
1288 re = _mm_shuffle_ps(a, b, _MM_SHUFFLE(2, 0, 2, 0));
1289 im = _mm_shuffle_ps(a, b, _MM_SHUFFLE(3, 1, 3, 1));
1291 static void storeInterleave2(
float* p, V re, V im)
noexcept
1293 _mm_storeu_ps(p, _mm_unpacklo_ps(re, im));
1294 _mm_storeu_ps(p + 4, _mm_unpackhi_ps(re, im));
1296 static void storeInterleave4(
float* p, V a, V b, V c, V d)
noexcept
1298 _MM_TRANSPOSE4_PS(a, b, c, d);
1299 _mm_storeu_ps(p, a); _mm_storeu_ps(p + 4, b);
1300 _mm_storeu_ps(p + 8, c); _mm_storeu_ps(p + 12, d);
1305struct Vec<double, 2>
1308 static V load(
const double* p)
noexcept {
return _mm_loadu_pd(p); }
1309 static void store(
double* p, V v)
noexcept { _mm_storeu_pd(p, v); }
1310 static V set1(
double x)
noexcept {
return _mm_set1_pd(x); }
1311 static V
add(V a, V b)
noexcept {
return _mm_add_pd(a, b); }
1312 static V sub(V a, V b)
noexcept {
return _mm_sub_pd(a, b); }
1313 static V mul(V a, V b)
noexcept {
return _mm_mul_pd(a, b); }
1314#if defined(DSPARK_SIMD_FMA)
1315 static V mulSub(V a, V b, V c, V d)
noexcept {
return _mm_fmsub_pd(a, b, _mm_mul_pd(c, d)); }
1316 static V mulAdd(V a, V b, V c, V d)
noexcept {
return _mm_fmadd_pd(a, b, _mm_mul_pd(c, d)); }
1317 static V madd(V a, V b, V c)
noexcept {
return _mm_fmadd_pd(a, b, c); }
1319 static V mulSub(V a, V b, V c, V d)
noexcept {
return _mm_sub_pd(_mm_mul_pd(a, b), _mm_mul_pd(c, d)); }
1320 static V mulAdd(V a, V b, V c, V d)
noexcept {
return _mm_add_pd(_mm_mul_pd(a, b), _mm_mul_pd(c, d)); }
1321 static V madd(V a, V b, V c)
noexcept {
return _mm_add_pd(_mm_mul_pd(a, b), c); }
1323 static V reverse(V v)
noexcept {
return _mm_shuffle_pd(v, v, 1); }
1324 static void loadDeinterleave(
const double* p, V& re, V& im)
noexcept
1326 const V a = _mm_loadu_pd(p), b = _mm_loadu_pd(p + 2);
1327 re = _mm_unpacklo_pd(a, b);
1328 im = _mm_unpackhi_pd(a, b);
1330 static void storeInterleave2(
double* p, V re, V im)
noexcept
1332 _mm_storeu_pd(p, _mm_unpacklo_pd(re, im));
1333 _mm_storeu_pd(p + 2, _mm_unpackhi_pd(re, im));
1335 static void storeInterleave4(
double* p, V a, V b, V c, V d)
noexcept
1337 _mm_storeu_pd(p, _mm_unpacklo_pd(a, b));
1338 _mm_storeu_pd(p + 2, _mm_unpacklo_pd(c, d));
1339 _mm_storeu_pd(p + 4, _mm_unpackhi_pd(a, b));
1340 _mm_storeu_pd(p + 6, _mm_unpackhi_pd(c, d));
1343#elif defined(DSPARK_SIMD_NEON)
1350 using V = float32x4_t;
1351 static V load(
const float* p)
noexcept {
return vld1q_f32(p); }
1352 static void store(
float* p, V v)
noexcept { vst1q_f32(p, v); }
1353 static V set1(
float x)
noexcept {
return vdupq_n_f32(x); }
1354 static V
add(V a, V b)
noexcept {
return vaddq_f32(a, b); }
1355 static V sub(V a, V b)
noexcept {
return vsubq_f32(a, b); }
1356 static V mul(V a, V b)
noexcept {
return vmulq_f32(a, b); }
1357 static V mulSub(V a, V b, V c, V d)
noexcept {
return vsubq_f32(vmulq_f32(a, b), vmulq_f32(c, d)); }
1358 static V mulAdd(V a, V b, V c, V d)
noexcept {
return vaddq_f32(vmulq_f32(a, b), vmulq_f32(c, d)); }
1361 static V madd(V a, V b, V c)
noexcept {
return vfmaq_f32(c, a, b); }
1362 static V reverse(V v)
noexcept {
const V r = vrev64q_f32(v);
return vextq_f32(r, r, 2); }
1363 static void loadDeinterleave(
const float* p, V& re, V& im)
noexcept
1365 const float32x4x2_t v = vld2q_f32(p);
1366 re = v.val[0]; im = v.val[1];
1368 static void storeInterleave2(
float* p, V re, V im)
noexcept
1370 float32x4x2_t v; v.val[0] = re; v.val[1] = im;
1373 static void storeInterleave4(
float* p, V a, V b, V c, V d)
noexcept
1375 float32x4x4_t v; v.val[0] = a; v.val[1] = b; v.val[2] = c; v.val[3] = d;
1381struct Vec<double, 2>
1383 using V = float64x2_t;
1384 static V load(
const double* p)
noexcept {
return vld1q_f64(p); }
1385 static void store(
double* p, V v)
noexcept { vst1q_f64(p, v); }
1386 static V set1(
double x)
noexcept {
return vdupq_n_f64(x); }
1387 static V
add(V a, V b)
noexcept {
return vaddq_f64(a, b); }
1388 static V sub(V a, V b)
noexcept {
return vsubq_f64(a, b); }
1389 static V mul(V a, V b)
noexcept {
return vmulq_f64(a, b); }
1390 static V mulSub(V a, V b, V c, V d)
noexcept {
return vsubq_f64(vmulq_f64(a, b), vmulq_f64(c, d)); }
1391 static V mulAdd(V a, V b, V c, V d)
noexcept {
return vaddq_f64(vmulq_f64(a, b), vmulq_f64(c, d)); }
1392 static V madd(V a, V b, V c)
noexcept {
return vfmaq_f64(c, a, b); }
1393 static V reverse(V v)
noexcept {
return vextq_f64(v, v, 1); }
1394 static void loadDeinterleave(
const double* p, V& re, V& im)
noexcept
1396 const float64x2x2_t v = vld2q_f64(p);
1397 re = v.val[0]; im = v.val[1];
1399 static void storeInterleave2(
double* p, V re, V im)
noexcept
1401 float64x2x2_t v; v.val[0] = re; v.val[1] = im;
1404 static void storeInterleave4(
double* p, V a, V b, V c, V d)
noexcept
1406 float64x2x4_t v; v.val[0] = a; v.val[1] = b; v.val[2] = c; v.val[3] = d;
1415#if defined(DSPARK_SIMD_AVX)
1423 static V load(
const float* p)
noexcept {
return _mm256_loadu_ps(p); }
1424 static void store(
float* p, V v)
noexcept { _mm256_storeu_ps(p, v); }
1425 static V set1(
float x)
noexcept {
return _mm256_set1_ps(x); }
1426 static V
add(V a, V b)
noexcept {
return _mm256_add_ps(a, b); }
1427 static V sub(V a, V b)
noexcept {
return _mm256_sub_ps(a, b); }
1428 static V mul(V a, V b)
noexcept {
return _mm256_mul_ps(a, b); }
1429#if defined(DSPARK_SIMD_FMA)
1430 static V mulSub(V a, V b, V c, V d)
noexcept {
return _mm256_fmsub_ps(a, b, _mm256_mul_ps(c, d)); }
1431 static V mulAdd(V a, V b, V c, V d)
noexcept {
return _mm256_fmadd_ps(a, b, _mm256_mul_ps(c, d)); }
1432 static V madd(V a, V b, V c)
noexcept {
return _mm256_fmadd_ps(a, b, c); }
1434 static V mulSub(V a, V b, V c, V d)
noexcept {
return _mm256_sub_ps(_mm256_mul_ps(a, b), _mm256_mul_ps(c, d)); }
1435 static V mulAdd(V a, V b, V c, V d)
noexcept {
return _mm256_add_ps(_mm256_mul_ps(a, b), _mm256_mul_ps(c, d)); }
1436 static V madd(V a, V b, V c)
noexcept {
return _mm256_add_ps(_mm256_mul_ps(a, b), c); }
1438 static V reverse(V v)
noexcept
1440 const V swapped = _mm256_permute2f128_ps(v, v, 1);
1441 return _mm256_permute_ps(swapped, _MM_SHUFFLE(0, 1, 2, 3));
1443 static void loadDeinterleave(
const float* p, V& re, V& im)
noexcept
1445 const V a = _mm256_loadu_ps(p), b = _mm256_loadu_ps(p + 8);
1446 const V lo = _mm256_permute2f128_ps(a, b, 0x20);
1447 const V hi = _mm256_permute2f128_ps(a, b, 0x31);
1448 re = _mm256_shuffle_ps(lo, hi, _MM_SHUFFLE(2, 0, 2, 0));
1449 im = _mm256_shuffle_ps(lo, hi, _MM_SHUFFLE(3, 1, 3, 1));
1451 static void storeInterleave2(
float* p, V re, V im)
noexcept
1453 const V lo = _mm256_unpacklo_ps(re, im);
1454 const V hi = _mm256_unpackhi_ps(re, im);
1455 _mm256_storeu_ps(p, _mm256_permute2f128_ps(lo, hi, 0x20));
1456 _mm256_storeu_ps(p + 8, _mm256_permute2f128_ps(lo, hi, 0x31));
1458 static void storeInterleave4(
float* p, V a, V b, V c, V d)
noexcept
1460 const V t0 = _mm256_unpacklo_ps(a, b), t1 = _mm256_unpackhi_ps(a, b);
1461 const V t2 = _mm256_unpacklo_ps(c, d), t3 = _mm256_unpackhi_ps(c, d);
1462 const V u0 = _mm256_shuffle_ps(t0, t2, _MM_SHUFFLE(1, 0, 1, 0));
1463 const V u1 = _mm256_shuffle_ps(t0, t2, _MM_SHUFFLE(3, 2, 3, 2));
1464 const V u2 = _mm256_shuffle_ps(t1, t3, _MM_SHUFFLE(1, 0, 1, 0));
1465 const V u3 = _mm256_shuffle_ps(t1, t3, _MM_SHUFFLE(3, 2, 3, 2));
1466 _mm256_storeu_ps(p, _mm256_permute2f128_ps(u0, u1, 0x20));
1467 _mm256_storeu_ps(p + 8, _mm256_permute2f128_ps(u2, u3, 0x20));
1468 _mm256_storeu_ps(p + 16, _mm256_permute2f128_ps(u0, u1, 0x31));
1469 _mm256_storeu_ps(p + 24, _mm256_permute2f128_ps(u2, u3, 0x31));
1474struct Vec<double, 4>
1477 static V load(
const double* p)
noexcept {
return _mm256_loadu_pd(p); }
1478 static void store(
double* p, V v)
noexcept { _mm256_storeu_pd(p, v); }
1479 static V set1(
double x)
noexcept {
return _mm256_set1_pd(x); }
1480 static V
add(V a, V b)
noexcept {
return _mm256_add_pd(a, b); }
1481 static V sub(V a, V b)
noexcept {
return _mm256_sub_pd(a, b); }
1482 static V mul(V a, V b)
noexcept {
return _mm256_mul_pd(a, b); }
1483#if defined(DSPARK_SIMD_FMA)
1484 static V mulSub(V a, V b, V c, V d)
noexcept {
return _mm256_fmsub_pd(a, b, _mm256_mul_pd(c, d)); }
1485 static V mulAdd(V a, V b, V c, V d)
noexcept {
return _mm256_fmadd_pd(a, b, _mm256_mul_pd(c, d)); }
1486 static V madd(V a, V b, V c)
noexcept {
return _mm256_fmadd_pd(a, b, c); }
1488 static V mulSub(V a, V b, V c, V d)
noexcept {
return _mm256_sub_pd(_mm256_mul_pd(a, b), _mm256_mul_pd(c, d)); }
1489 static V mulAdd(V a, V b, V c, V d)
noexcept {
return _mm256_add_pd(_mm256_mul_pd(a, b), _mm256_mul_pd(c, d)); }
1490 static V madd(V a, V b, V c)
noexcept {
return _mm256_add_pd(_mm256_mul_pd(a, b), c); }
1492 static V reverse(V v)
noexcept
1494 const V swapped = _mm256_permute2f128_pd(v, v, 1);
1495 return _mm256_permute_pd(swapped, 0x5);
1497 static void loadDeinterleave(
const double* p, V& re, V& im)
noexcept
1499 const V a = _mm256_loadu_pd(p), b = _mm256_loadu_pd(p + 4);
1500 const V lo = _mm256_permute2f128_pd(a, b, 0x20);
1501 const V hi = _mm256_permute2f128_pd(a, b, 0x31);
1502 re = _mm256_unpacklo_pd(lo, hi);
1503 im = _mm256_unpackhi_pd(lo, hi);
1505 static void storeInterleave2(
double* p, V re, V im)
noexcept
1507 const V lo = _mm256_unpacklo_pd(re, im);
1508 const V hi = _mm256_unpackhi_pd(re, im);
1509 _mm256_storeu_pd(p, _mm256_permute2f128_pd(lo, hi, 0x20));
1510 _mm256_storeu_pd(p + 4, _mm256_permute2f128_pd(lo, hi, 0x31));
1512 static void storeInterleave4(
double* p, V a, V b, V c, V d)
noexcept
1514 const V t0 = _mm256_unpacklo_pd(a, b), t1 = _mm256_unpackhi_pd(a, b);
1515 const V t2 = _mm256_unpacklo_pd(c, d), t3 = _mm256_unpackhi_pd(c, d);
1516 _mm256_storeu_pd(p, _mm256_permute2f128_pd(t0, t2, 0x20));
1517 _mm256_storeu_pd(p + 4, _mm256_permute2f128_pd(t1, t3, 0x20));
1518 _mm256_storeu_pd(p + 8, _mm256_permute2f128_pd(t0, t2, 0x31));
1519 _mm256_storeu_pd(p + 12, _mm256_permute2f128_pd(t1, t3, 0x31));
1548template <
typename T>
1549void firCorrelate(
const T* x,
const T* h,
int taps, T* DSPARK_RESTRICT y,
int n, T gain)
noexcept
1551 static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>,
"SimdOps: only float and double are supported");
1552 constexpr int W = kVecWidth<T>;
1554 using V =
typename O::V;
1555 const V g = O::set1(gain);
1557 for (; i + 4 * W <= n; i += 4 * W)
1559 V a0 = O::set1(T(0)), a1 = a0, a2 = a0, a3 = a0;
1560 const T* xp = x + i;
1561 for (
int j = 0; j < taps; ++j)
1563 const V hj = O::set1(h[j]);
1564 a0 = O::madd(hj, O::load(xp + j), a0);
1565 a1 = O::madd(hj, O::load(xp + j + W), a1);
1566 a2 = O::madd(hj, O::load(xp + j + 2 * W), a2);
1567 a3 = O::madd(hj, O::load(xp + j + 3 * W), a3);
1569 O::store(y + i, O::mul(a0, g));
1570 O::store(y + i + W, O::mul(a1, g));
1571 O::store(y + i + 2 * W, O::mul(a2, g));
1572 O::store(y + i + 3 * W, O::mul(a3, g));
1574 for (; i + W <= n; i += W)
1576 V a = O::set1(T(0));
1577 for (
int j = 0; j < taps; ++j)
1578 a = O::madd(O::set1(h[j]), O::load(x + i + j), a);
1579 O::store(y + i, O::mul(a, g));
1586 V a = O::set1(T(0));
1587 for (
int j = 0; j < taps; ++j)
1588 a = O::madd(O::set1(h[j]), O::set1(x[i + j]), a);
1590 O::store(lanes, O::mul(a, g));