From ba87df80091a7a52cc108b124b2fe582ed51340c Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 31 May 2020 12:48:52 +0200 Subject: [PATCH] Move diff to the new format --- benchmarks/BM_diff.cpp | 12 +++++--- src/sfizz/SIMDHelpers.cpp | 48 +++++++++++++++++++++++++++--- src/sfizz/SIMDHelpers.h | 61 ++++++++++++++------------------------- src/sfizz/SIMDSSE.cpp | 31 -------------------- tests/SIMDHelpersT.cpp | 9 ++++-- 5 files changed, 80 insertions(+), 81 deletions(-) diff --git a/benchmarks/BM_diff.cpp b/benchmarks/BM_diff.cpp index 911556bb..2d2271bd 100644 --- a/benchmarks/BM_diff.cpp +++ b/benchmarks/BM_diff.cpp @@ -37,28 +37,32 @@ public: BENCHMARK_DEFINE_F(DiffArray, Diff_Scalar)(benchmark::State& state) { for (auto _ : state) { - sfz::diff(input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::diff, false); + sfz::diff(input, absl::MakeSpan(output)); } } BENCHMARK_DEFINE_F(DiffArray, Diff_SIMD)(benchmark::State& state) { for (auto _ : state) { - sfz::diff(input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::diff, true); + sfz::diff(input, absl::MakeSpan(output)); } } BENCHMARK_DEFINE_F(DiffArray, Diff_Scalar_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::diff(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::diff, false); + sfz::diff(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } BENCHMARK_DEFINE_F(DiffArray, Diff_SIMD_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::diff(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::diff, true); + sfz::diff(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index 4dbff456..da87bc8e 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -569,8 +569,8 @@ void cumsum(const float* input, float* output, unsigned size) noexcept const auto* lastAligned = prevAligned(sentinel); while (unaligned(input, output) && output < lastAligned) { - *output = *(output - 1) + *input++; - output++; + *output = *(output - 1) + *input; + incrementAll(input, output); } auto mmOutput = _mm_set_ps1(*(output - 1)); @@ -589,8 +589,48 @@ void cumsum(const float* input, float* output, unsigned size) noexcept } while (output < sentinel) { - *output = *(output - 1) + *input++; - output++; + *output = *(output - 1) + *input; + incrementAll(input, output); + } +} + +template <> +void diff(const float* input, float* output, unsigned size) noexcept +{ + if (size == 0) + return; + + const auto sentinel = output + size; + *output++ = *input++; + + if (getSIMDOpStatus(SIMDOps::diff)) { +#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 - *(input - 1); + incrementAll(input, output); + } + + auto mmBase = _mm_set_ps1(*(input - 1)); + while (output < lastAligned) { + auto mmOutput = _mm_load_ps(input); + auto mmNextBase = _mm_shuffle_ps(mmOutput, mmOutput, _MM_SHUFFLE(3, 3, 3, 3)); + mmOutput = _mm_sub_ps(mmOutput, mmBase); + mmBase = mmNextBase; + mmOutput = _mm_sub_ps(mmOutput, _mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(mmOutput), 4))); + _mm_store_ps(output, mmOutput); + incrementAll<4>(input, output); + } + // fallthrough from lastAligned to sentinel + } +#endif + } + + while (output < sentinel) { + *output = *input - *(input - 1); + incrementAll(input, output); } } diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index 509766f6..5d3fea02 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -590,21 +590,10 @@ T meanSquared(absl::Span vector) noexcept return meanSquared(vector.data(), vector.size()); } -namespace _internals { - template - inline void snippetCumsum(const T*& input, T*& output) - { - *output = *(output - 1) + *input++; - output++; - } -} - /** * @brief Computes the cumulative sum of a span. * The first output is the same as the first input. * - * The output size will be the minimum of the input span and output span sizes. - * * @tparam T the underlying type * @param input * @param output @@ -620,8 +609,8 @@ void cumsum(const T* input, T* output, unsigned size) noexcept *output++ = *input++; while (output < sentinel) { - *output = *(output - 1) + *input++; - output++; + *output = *(output - 1) + *input; + incrementAll(input, output); } } @@ -672,44 +661,38 @@ void sfzInterpolationCast(absl::Span floatJumps, absl::Span jumps, _internals::snippetSFZInterpolationCast(floatJump, jump, coeff); } -namespace _internals { - template - inline void snippetDiff(const T*& input, T*& output) - { - *output = *input - *(input - 1); - output++; - input++; - } -} - /** * @brief Computes the differential of a span (successive differences). * The first output is the same as the first input. * - * The output size will be the minimum of the input span and output span sizes. - * * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version - * @param vector - * @return T + * @param input + * @param output + * @param size */ -template -void diff(absl::Span input, absl::Span output) noexcept +template +void diff(const T* input, T* output, unsigned size) noexcept { - CHECK(output.size() >= input.size()); - if (input.size() == 0) + if (size == 0) return; - auto out = output.data(); - auto in = input.data(); - const auto sentinel = in + std::min(input.size(), output.size()); + const auto sentinel = output + size; - *out++ = *in++; - while (in < sentinel) - _internals::snippetDiff(in, out); + *output++ = *input++; + while (output < sentinel) { + *output = *input - *(input - 1); + incrementAll(input, output); + } } template <> -void diff(absl::Span input, absl::Span output) noexcept; +void diff(const float* input, float* output, unsigned size) noexcept; + +template +void diff(absl::Span input, absl::Span output) noexcept +{ + CHECK_SPAN_SIZES(input, output); + diff(input.data(), output.data(), minSpanSize(input, output)); +} } // namespace sfz diff --git a/src/sfizz/SIMDSSE.cpp b/src/sfizz/SIMDSSE.cpp index 8e04801d..d3c023db 100644 --- a/src/sfizz/SIMDSSE.cpp +++ b/src/sfizz/SIMDSSE.cpp @@ -16,35 +16,4 @@ constexpr uintptr_t TypeAlignment = 4; -template <> -void sfz::diff(absl::Span input, absl::Span output) noexcept -{ - CHECK(output.size() >= input.size()); - if (input.size() == 0) - return; - - auto out = output.data(); - auto in = input.data(); - const auto sentinel = in + std::min(input.size(), output.size()); - const auto lastAligned = prevAligned(sentinel); - - *out++ = *in++; - while (unaligned(in, out) && in < lastAligned) - _internals::snippetDiff(in, out); - - auto mmBase = _mm_set_ps1(*(in - 1)); - while (in < lastAligned) { - auto mmOutput = _mm_load_ps(in); - auto mmNextBase = _mm_shuffle_ps(mmOutput, mmOutput, _MM_SHUFFLE(3, 3, 3, 3)); - mmOutput = _mm_sub_ps(mmOutput, mmBase); - mmBase = mmNextBase; - mmOutput = _mm_sub_ps(mmOutput, _mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(mmOutput), 4))); - _mm_store_ps(out, mmOutput); - incrementAll(in, out); - } - - while (in < sentinel) - _internals::snippetDiff(in, out); -} - #endif // SFIZZ_HAVE_SSE2 diff --git a/tests/SIMDHelpersT.cpp b/tests/SIMDHelpersT.cpp index 15003d9a..0e15fa15 100644 --- a/tests/SIMDHelpersT.cpp +++ b/tests/SIMDHelpersT.cpp @@ -720,7 +720,8 @@ TEST_CASE("[Helpers] Diff") std::array input { 1.1f, 2.3f, 3.6f, 5.0f, 6.5f, 8.1f }; std::array output; std::array expected { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f }; - sfz::diff(input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::diff, false); + sfz::diff(input, absl::MakeSpan(output)); REQUIRE(approxEqual(output, expected)); } @@ -731,8 +732,10 @@ TEST_CASE("[Helpers] Diff (SIMD vs Scalar)") std::vector outputSIMD(bigBufferSize); sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); sfz::linearRamp(absl::MakeSpan(input), 0.0f, 0.1f); - sfz::diff(input, absl::MakeSpan(outputScalar)); - sfz::diff(input, absl::MakeSpan(outputSIMD)); + sfz::setSIMDOpStatus(sfz::SIMDOps::diff, false); + sfz::diff(input, absl::MakeSpan(outputScalar)); + sfz::setSIMDOpStatus(sfz::SIMDOps::diff, true); + sfz::diff(input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); }