From 3cb816406824f00bcd8db74b6afe92ebade99619 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 31 May 2020 09:24:44 +0200 Subject: [PATCH] Move add to the new format --- benchmarks/BM_add.cpp | 24 ++++++++----- src/sfizz/SIMDHelpers.cpp | 63 +++++++++++++++++++++++++++++--- src/sfizz/SIMDHelpers.h | 75 ++++++++++++++++++--------------------- src/sfizz/SIMDSSE.cpp | 43 ---------------------- tests/SIMDHelpersT.cpp | 16 +++++---- 5 files changed, 118 insertions(+), 103 deletions(-) diff --git a/benchmarks/BM_add.cpp b/benchmarks/BM_add.cpp index 893b2392..5e2d278e 100644 --- a/benchmarks/BM_add.cpp +++ b/benchmarks/BM_add.cpp @@ -36,56 +36,64 @@ public: BENCHMARK_DEFINE_F(AddArray, Value_Scalar)(benchmark::State& state) { for (auto _ : state) { - sfz::add(1.1f, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::add, false); + sfz::add(1.1f, absl::MakeSpan(output)); } } BENCHMARK_DEFINE_F(AddArray, Value_SIMD)(benchmark::State& state) { for (auto _ : state) { - sfz::add(1.1f, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::add, true); + sfz::add(1.1f, absl::MakeSpan(output)); } } BENCHMARK_DEFINE_F(AddArray, Value_Scalar_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::add(1.1f, absl::MakeSpan(output).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::add, false); + sfz::add(1.1f, absl::MakeSpan(output).subspan(1)); } } BENCHMARK_DEFINE_F(AddArray, Value_SIMD_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::add(1.1f, absl::MakeSpan(output).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::add, true); + sfz::add(1.1f, absl::MakeSpan(output).subspan(1)); } } BENCHMARK_DEFINE_F(AddArray, Scalar)(benchmark::State& state) { for (auto _ : state) { - sfz::add(input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::add, false); + sfz::add(input, absl::MakeSpan(output)); } } BENCHMARK_DEFINE_F(AddArray, SIMD)(benchmark::State& state) { for (auto _ : state) { - sfz::add(input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::add, true); + sfz::add(input, absl::MakeSpan(output)); } } BENCHMARK_DEFINE_F(AddArray, Scalar_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::add(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::add, false); + sfz::add(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } BENCHMARK_DEFINE_F(AddArray, SIMD_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::add(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::add, true); + sfz::add(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index bcb56197..245246be 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -145,7 +145,7 @@ void applyGain(float gain, const float* input, float* output, unsigned si #if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 if (cpuInfo.has_sse()) { const auto* lastAligned = prevAligned(sentinel); - const auto mmGain = _mm_set_ps1(gain); + const auto mmGain = _mm_set1_ps(gain); while (unaligned(input, output) && output < lastAligned) *output++ = gain * (*input++); @@ -278,7 +278,7 @@ float linearRamp(float* output, float start, float step, unsigned size) n #if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 if (cpuInfo.has_sse()) { const auto* lastAligned = prevAligned(sentinel); - while (unaligned(output) && output < lastAligned){ + while (unaligned(output) && output < lastAligned) { *output++ = start; start += step; } @@ -289,7 +289,7 @@ float linearRamp(float* output, float start, float step, unsigned size) n mmStart = _mm_add_ps(mmStart, mmStep); _mm_store_ps(output, mmStart); mmStart = _mm_shuffle_ps(mmStart, mmStart, _MM_SHUFFLE(3, 3, 3, 3)); - incrementAll<4>( output); + incrementAll<4>(output); } start = _mm_cvtss_f32(mmStart) + step; // fallthrough from lastAligned to sentinel @@ -313,7 +313,7 @@ float multiplicativeRamp(float* output, float start, float step, unsigned #if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 if (cpuInfo.has_sse()) { const auto* lastAligned = prevAligned(sentinel); - while (unaligned(output) && output < lastAligned){ + while (unaligned(output) && output < lastAligned) { *output++ = start; start *= step; } @@ -324,7 +324,7 @@ float multiplicativeRamp(float* output, float start, float step, unsigned mmStart = _mm_mul_ps(mmStart, mmStep); _mm_store_ps(output, mmStart); mmStart = _mm_shuffle_ps(mmStart, mmStart, _MM_SHUFFLE(3, 3, 3, 3)); - incrementAll<4>( output); + incrementAll<4>(output); } start = _mm_cvtss_f32(mmStart) * step; // fallthrough from lastAligned to sentinel @@ -339,4 +339,57 @@ float multiplicativeRamp(float* output, float start, float step, unsigned return start; } +template <> +void add(const float* input, float* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + + if (getSIMDOpStatus(SIMDOps::add)) { +#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 + if (cpuInfo.has_sse()) { + const auto* lastAligned = prevAligned(sentinel); + + while (unaligned(input, output) && output < lastAligned) + *output++ += *input++; + + while (output < lastAligned) { + _mm_store_ps(output, _mm_add_ps(_mm_load_ps(output), _mm_load_ps(input))); + incrementAll<4>(input, output); + } + // fallthrough from lastAligned to sentinel + } +#endif + } + + while (output < sentinel) + *output++ += *input++; +} + +template <> +void add(float value, float* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + + if (getSIMDOpStatus(SIMDOps::add)) { +#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 + if (cpuInfo.has_sse()) { + const auto* lastAligned = prevAligned(sentinel); + + while (unaligned(output) && output < lastAligned) + *output++ += value; + + const auto mmValue = _mm_set1_ps(value); + while (output < lastAligned) { + _mm_store_ps(output, _mm_add_ps(_mm_load_ps(output), mmValue)); + incrementAll<4>(output); + } + // fallthrough from lastAligned to sentinel + } +#endif + } + + while (output < sentinel) + *output++ += value; +} + } diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index ef9fd2c7..24370bb0 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -369,15 +369,6 @@ T linearRamp(absl::Span output, T start, T step) noexcept return linearRamp(output.data(), start, step, output.size()); } -namespace _internals { - template - inline void snippetRampMultiplicative(T*& output, T& value, T step) - { - *output++ = value; - value *= step; - } -} - /** * @brief Compute a multiplicative ramp blockwise between 2 values * @@ -408,55 +399,57 @@ T multiplicativeRamp(absl::Span output, T start, T step) noexcept } -namespace _internals { - template - inline void snippetAdd(const T*& input, T*& output) - { - *output++ += *input++; - } - template - inline void snippetAdd(const T value, T*& output) - { - *output++ += value; - } -} - /** * @brief Add an input span to the output span * - * The output size will be the minimum of the gain span, input span and output span sizes. - * * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version * @param input * @param output + * @param size */ -template +template +void add(const T* input, T* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + while (output < sentinel) + *output++ += *input++; +} + +template <> +void add(const float* input, float* output, unsigned size) noexcept; + +template void add(absl::Span input, absl::Span output) noexcept { - CHECK(output.size() >= input.size()); - auto* in = input.begin(); - auto* out = output.begin(); - auto* sentinel = out + min(input.size(), output.size()); - while (out < sentinel) - _internals::snippetAdd(in, out); + CHECK_SPAN_SIZES(input, output); + add(input.data(), output.data(), minSpanSize(input, output)); +} + +/** + * @brief Add a value inplace + * + * @tparam T the underlying type + * @param value + * @param output + * @param size + */ +template +void add(T value, T* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + while (output < sentinel) + *output++ += value; } template <> -void add(absl::Span input, absl::Span output) noexcept; +void add(float value, float* output, unsigned size) noexcept; -template +template void add(T value, absl::Span output) noexcept { - auto* out = output.begin(); - auto* sentinel = output.end(); - while (out < sentinel) - _internals::snippetAdd(value, out); + add(value, output.data(), output.size()); } -template <> -void add(float value, absl::Span output) noexcept; - namespace _internals { template inline void snippetSubtract(const T*& input, T*& output) diff --git a/src/sfizz/SIMDSSE.cpp b/src/sfizz/SIMDSSE.cpp index a1258e85..aca877a6 100644 --- a/src/sfizz/SIMDSSE.cpp +++ b/src/sfizz/SIMDSSE.cpp @@ -16,49 +16,6 @@ constexpr uintptr_t TypeAlignment = 4; - - -template <> -void sfz::add(absl::Span input, absl::Span output) noexcept -{ - CHECK(output.size() >= input.size()); - auto* in = input.begin(); - auto* out = output.begin(); - auto* sentinel = out + min(input.size(), output.size()); - const auto* lastAligned = prevAligned(sentinel); - - while (unaligned(in, out) && out < lastAligned) - _internals::snippetAdd(in, out); - - while (out < lastAligned) { - _mm_store_ps(out, _mm_add_ps(_mm_load_ps(in), _mm_load_ps(out))); - incrementAll(in, out); - } - - while (out < sentinel) - _internals::snippetAdd(in, out); -} - -template <> -void sfz::add(float value, absl::Span output) noexcept -{ - auto* out = output.begin(); - auto* sentinel = output.end(); - const auto* lastAligned = prevAligned(sentinel); - - while (unaligned(out) && out < lastAligned) - _internals::snippetAdd(value, out); - - auto mmValue = _mm_set_ps1(value); - while (out < lastAligned) { - _mm_store_ps(out, _mm_add_ps(mmValue, _mm_load_ps(out))); - out += TypeAlignment; - } - - while (out < sentinel) - _internals::snippetAdd(value, out); -} - template <> void sfz::subtract(absl::Span input, absl::Span output) noexcept { diff --git a/tests/SIMDHelpersT.cpp b/tests/SIMDHelpersT.cpp index 6e67ee78..b38774f3 100644 --- a/tests/SIMDHelpersT.cpp +++ b/tests/SIMDHelpersT.cpp @@ -447,7 +447,8 @@ TEST_CASE("[Helpers] Add") std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array expected { 2.0f, 3.0f, 4.0f, 5.0f, 6.0f }; - sfz::add(input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::add, false); + sfz::add(input, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -456,7 +457,8 @@ TEST_CASE("[Helpers] Add (SIMD)") std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array expected { 2.0f, 3.0f, 4.0f, 5.0f, 6.0f }; - sfz::add(input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::add, true); + sfz::add(input, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -469,8 +471,10 @@ TEST_CASE("[Helpers] Add (SIMD vs scalar)") absl::c_fill(outputScalar, 0.0f); absl::c_fill(outputSIMD, 0.0f); - sfz::add(input, absl::MakeSpan(outputScalar)); - sfz::add(input, absl::MakeSpan(outputSIMD)); + sfz::setSIMDOpStatus(sfz::SIMDOps::add, false); + sfz::add(input, absl::MakeSpan(outputScalar)); + sfz::setSIMDOpStatus(sfz::SIMDOps::add, true); + sfz::add(input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } @@ -631,8 +635,8 @@ TEST_CASE("[Helpers] copy (SIMD vs scalar)") absl::c_fill(outputScalar, 0.0f); absl::c_fill(outputSIMD, 0.0f); - sfz::add(input, absl::MakeSpan(outputScalar)); - sfz::add(input, absl::MakeSpan(outputSIMD)); + sfz::copy(input, absl::MakeSpan(outputScalar)); + sfz::copy(input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); }