diff --git a/cmake/SfizzSIMDSourceFiles.cmake b/cmake/SfizzSIMDSourceFiles.cmake index edca20e6..efd86bb7 100644 --- a/cmake/SfizzSIMDSourceFiles.cmake +++ b/cmake/SfizzSIMDSourceFiles.cmake @@ -13,6 +13,7 @@ macro(sfizz_add_simd_sources SOURCES_VAR PREFIX) set_source_files_properties( ${PREFIX}/sfizz/effects/impl/ResonantStringAVX.cpp ${PREFIX}/sfizz/effects/impl/ResonantArrayAVX.cpp + ${PREFIX}/sfizz/SIMDHelpers.cpp PROPERTIES COMPILE_FLAGS "-mavx") endif() endif() diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index 40a40e36..f495127f 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -5,7 +5,7 @@ #include "SIMDConfig.h" #if SFIZZ_HAVE_SSE2 -#include +#include #include #endif @@ -149,7 +149,17 @@ void applyGain(float gain, const float* input, float* output, unsigned si if (getSIMDOpStatus(SIMDOps::gain)) { #if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 - if (cpuInfo.has_sse()) { + if (cpuInfo.has_avx()) { + const auto* lastAligned = prevAligned<32>(sentinel); + const auto mmGain = _mm256_set1_ps(gain); + while (unaligned<32>(input, output) && output < lastAligned) + *output++ = gain * (*input++); + + while (output < lastAligned) { + _mm256_store_ps(output, _mm256_mul_ps(mmGain, _mm256_load_ps(input))); + incrementAll<8>(input, output); + } + } else if (cpuInfo.has_sse()) { const auto* lastAligned = prevAligned(sentinel); const auto mmGain = _mm_set1_ps(gain); while (unaligned(input, output) && output < lastAligned) @@ -175,7 +185,16 @@ void applyGain(const float* gain, const float* input, float* output, unsi if (getSIMDOpStatus(SIMDOps::gain)) { #if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 - if (cpuInfo.has_sse()) { + if (cpuInfo.has_avx()) { + const auto* lastAligned = prevAligned<32>(sentinel); + while (unaligned<32>(input, output) && output < lastAligned) + *output++ = (*gain++) * (*input++); + + while (output < lastAligned) { + _mm256_store_ps(output, _mm256_mul_ps(_mm256_load_ps(gain), _mm256_load_ps(input))); + incrementAll<8>(input, output); + } + } else if (cpuInfo.has_sse()) { const auto* lastAligned = prevAligned(sentinel); while (unaligned(input, output) && output < lastAligned) diff --git a/tests/SIMDHelpersT.cpp b/tests/SIMDHelpersT.cpp index 0e15fa15..415406fd 100644 --- a/tests/SIMDHelpersT.cpp +++ b/tests/SIMDHelpersT.cpp @@ -273,82 +273,98 @@ TEST_CASE("[Helpers] Interleaved write SIMD vs Scalar") TEST_CASE("[Helpers] Gain, single") { - std::array input { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; - std::array output { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; - std::array expected { fillValue, fillValue, fillValue, fillValue, fillValue }; - sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); - sfz::applyGain(fillValue, input, absl::MakeSpan(output)); - REQUIRE(output == expected); + std::array input; + std::array expected; + absl::c_fill(input, 1.0f); + absl::c_fill(expected, fillValue); + + SECTION("Scalar") + { + std::array output; + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); + sfz::applyGain(fillValue, input, absl::MakeSpan(output)); + REQUIRE(output == expected); + } + + SECTION("SIMD") + { + std::array output; + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); + sfz::applyGain(fillValue, input, absl::MakeSpan(output)); + REQUIRE(output == expected); + } } TEST_CASE("[Helpers] Gain, single and inplace") { - std::array buffer { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; - std::array expected { fillValue, fillValue, fillValue, fillValue, fillValue }; - sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); - sfz::applyGain(fillValue, buffer, absl::MakeSpan(buffer)); - REQUIRE(buffer == expected); + std::array expected; + std::array buffer; + absl::c_fill(expected, fillValue); + SECTION("Scalar") + { + absl::c_fill(buffer, 1.0f); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); + sfz::applyGain(fillValue, buffer, absl::MakeSpan(buffer)); + REQUIRE(buffer == expected); + } + SECTION("SIMD") + { + absl::c_fill(buffer, 1.0f); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); + sfz::applyGain(fillValue, buffer, absl::MakeSpan(buffer)); + REQUIRE(buffer == expected); + } } TEST_CASE("[Helpers] Gain, spans") { - std::array input { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; - std::array gain { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; - std::array output { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; - std::array expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; - sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); - sfz::applyGain(gain, input, absl::MakeSpan(output)); - REQUIRE(output == expected); + std::array input; + std::array gain; + std::array expected; + absl::c_fill(input, 1.0f); + absl::c_iota(gain, 1.0f); + absl::c_iota(expected, 1.0f); + + SECTION("Scalar") + { + std::array output; + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); + sfz::applyGain(gain, input, absl::MakeSpan(output)); + REQUIRE(output == expected); + } + + SECTION("SIMD") + { + std::array output; + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); + sfz::applyGain(gain, input, absl::MakeSpan(output)); + REQUIRE(output == expected); + } } TEST_CASE("[Helpers] Gain, spans and inplace") { - std::array buffer { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; - std::array gain { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; - std::array expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; - sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); - sfz::applyGain(gain, buffer, absl::MakeSpan(buffer)); - REQUIRE(buffer == expected); -} + std::array buffer; + std::array gain; + std::array expected; + absl::c_iota(gain, 1.0f); + absl::c_iota(expected, 1.0f); -TEST_CASE("[Helpers] Gain, single (SIMD)") -{ - std::array input { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; - std::array output { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; - std::array expected { fillValue, fillValue, fillValue, fillValue, fillValue }; - sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); - sfz::applyGain(fillValue, input, absl::MakeSpan(output)); - REQUIRE(output == expected); -} + SECTION("Scalar") + { + absl::c_fill(buffer, 1.0f); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); + sfz::applyGain(gain, buffer, absl::MakeSpan(buffer)); + REQUIRE(buffer == expected); + } -TEST_CASE("[Helpers] Gain, single and inplace (SIMD)") -{ - std::array buffer { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; - std::array expected { fillValue, fillValue, fillValue, fillValue, fillValue }; - sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); - sfz::applyGain(fillValue, buffer, absl::MakeSpan(buffer)); - REQUIRE(buffer == expected); -} - -TEST_CASE("[Helpers] Gain, spans (SIMD)") -{ - std::array input { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; - std::array gain { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; - std::array output { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; - std::array expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; - sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); - sfz::applyGain(gain, input, absl::MakeSpan(output)); - REQUIRE(output == expected); -} - -TEST_CASE("[Helpers] Gain, spans and inplace (SIMD)") -{ - std::array buffer { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; - std::array gain { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; - std::array expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; - sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); - sfz::applyGain(gain, buffer, absl::MakeSpan(buffer)); - REQUIRE(buffer == expected); + SECTION("SIMD") + { + absl::c_fill(buffer, 1.0f); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); + sfz::applyGain(gain, buffer, absl::MakeSpan(buffer)); + REQUIRE(buffer == expected); + } } TEST_CASE("[Helpers] Linear Ramp")