Use Simd operations for audio sanitization
- Dominant language
- C++
- Stars
- 10.4k
- Forks
- 1.3k
- Avg merge
- 2d 13h
- Merged PRs (30d)
- 7
Description
### Enhancement Summary
We have a loop that goes over a large amount of samples, and calls std::isfinite on every sample. Instead, we can use the following function (generated by gemini flash 3.5, to get the concept):
```
#include
#include
#include
#include
// --- Architecture & Feature Detection ---
#if defined(__STDC_IEC_559__) || defined(__alpha__) || defined(__ia64__) || defined(_M_X64) || defined(_M_IX86) || defined(__arm__) || defined(__aarch64__)
#define USE_IEEE754_BIT_TRICKS 1
#else
#define USE_IEEE754_BIT_TRICKS 0
#endif
#if defined(__AVX2__) || defined(_M_AVX2)
#include
#define HAS_AVX2_SIMD 1
#else
#define HAS_AVX2_SIMD 0
#endif
#if defined(__ARM_NEON) || defined(__ARM_NEON__)
#include
#define HAS_NEON_SIMD 1
#else
#define HAS_NEON_SIMD 0
#endif
bool verify_all_floats_finite(const float* array, size_t size) {
size_t i = 0;
// Process in chunks of 512 floats to balance SIMD throughput and early exit
constexpr size_t CHUNK_SIZE = 512;
#if HAS_AVX2_SIMD && USE_IEEE754_BIT_TRICKS
__m256i exp_mask = _mm256_set1_epi32(0x7F800000);
while (i + CHUNK_SIZE <= size) {
__m256i global_check = _mm256_setzero_si256();
// Inner loop: Completely branchless for 512 floats (64 iterations of 8 floats)
for (size_t j = 0; j < CHUNK_SIZE; j += 8) {
__m256i data = _mm256_loadu_si256(reinterpret_cast(array + i + j));
__m256i exp = _mm256_and_si256(data, exp_mask);
__m256i is_not_finite = _mm256_cmpeq_epi32(exp, exp_mask);
global_check = _mm256_or_si256(global_check, is_not_finite);
}
// Check once per chunk
int move_mask = _mm256_movemask_ps(_mm256_castsi256_ps(global_check));
if (move_mask != 0) {
return false; // Blow-up detected early! Exit immediately.
}
i += CHUNK_SIZE;
}
#elif HAS_NEON_SIMD && USE_IEEE754_BIT_TRICKS
uint32x4_t exp_mask = vdupq_n_u32(0x7F800000);
while (i + CHUNK_SIZE <= size) {
uint32x4_t global_check = vdupq_n_u32(0);
// Inner loop: Branchless for 512 floats (128 iterations of 4 floats)
for (size_t j = 0; j < CHUNK_SIZE; j += 4) {
uint32x4_t data = vld1q_u32(reinterpret_cast(array + i + j));
uint32x4_t exp = vandq_u32(data, exp_mask);
uint32x4_t is_not_finite = vceqq_u32(exp, exp_mask);
global_check = vorrq_u32(global_check, is_not_finite);
}
// Check once per chunk
if (vmaxvq_u32(global_check) != 0) {
return false; // Early exit on Apple Silicon / ARM
}
i += CHUNK_SIZE;
}
#endif
// --- Residual/Tail Handling ---
// Handles leftover elements if size is not a multiple of 512,
// or acts as the entire function if SIMD/IEEE754 isn't supported.
for (; i < size; ++i) {
#if USE_IEEE754_BIT_TRICKS
uint32_t u;
std::memcpy(&u, &array[i], sizeof(float));
if ((u & 0x7F800000) == 0x7F800000) {
return false;
}
#else
if (!std::isfinite(array[i])) {
return false;
}
#endif
}
return true;
}
```
### Implementation Details / Mockup
Should yield far more better performance
### Please search the issue tracker for existing feature requests before submitting your own.
- [x] I have searched all existing issues and confirmed that this is not a duplicate.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.