From 353dfa397367f129dbc4695d7b6fb72b7d2e126f Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 30 May 2020 10:41:50 +0200 Subject: [PATCH 01/42] Moved defaultAlignment to config --- src/sfizz/AudioBuffer.h | 4 ++-- src/sfizz/Buffer.h | 4 ++-- src/sfizz/Config.h | 2 +- src/sfizz/FilePool.h | 2 +- tests/BufferT.cpp | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sfizz/AudioBuffer.h b/src/sfizz/AudioBuffer.h index 4c104e35..9488243e 100644 --- a/src/sfizz/AudioBuffer.h +++ b/src/sfizz/AudioBuffer.h @@ -26,8 +26,8 @@ namespace sfz * @tparam MaxChannels the maximum number of channels in the buffer * @tparam Alignment the alignment for the buffers */ -template class AudioBuffer { public: diff --git a/src/sfizz/Buffer.h b/src/sfizz/Buffer.h index 89acfa36..9644f17d 100644 --- a/src/sfizz/Buffer.h +++ b/src/sfizz/Buffer.h @@ -119,9 +119,9 @@ private: * * @tparam Type The buffer type * @tparam Alignment the required alignment in bytes (defaults to - * SIMDConfig::defaultAlignment) + * config::defaultAlignment) */ -template +template class Buffer { public: using value_type = typename std::remove_cv::type; diff --git a/src/sfizz/Config.h b/src/sfizz/Config.h index 9ed09c8b..7e1eaa42 100644 --- a/src/sfizz/Config.h +++ b/src/sfizz/Config.h @@ -58,6 +58,7 @@ namespace config { constexpr uint16_t numCCs { 512 }; constexpr int maxCurves { 256 }; constexpr int chunkSize { 1024 }; + constexpr unsigned int defaultAlignment { 16 }; constexpr int filtersInPool { maxVoices * 2 }; constexpr int excessFileFrames { 8 }; /** @@ -98,7 +99,6 @@ namespace config { // Enable or disable SIMD accelerators by default namespace SIMDConfig { - constexpr unsigned int defaultAlignment { 16 }; constexpr bool writeInterleaved { true }; constexpr bool readInterleaved { true }; constexpr bool fill { true }; diff --git a/src/sfizz/FilePool.h b/src/sfizz/FilePool.h index b542e8bb..25eaf068 100644 --- a/src/sfizz/FilePool.h +++ b/src/sfizz/FilePool.h @@ -43,7 +43,7 @@ #include namespace sfz { -using FileAudioBuffer = AudioBuffer; using FileAudioBufferPtr = std::shared_ptr; diff --git a/tests/BufferT.cpp b/tests/BufferT.cpp index 8d43291d..ed5f986f 100644 --- a/tests/BufferT.cpp +++ b/tests/BufferT.cpp @@ -41,8 +41,8 @@ template void checkBoundaries(sfz::Buffer& buffer, int expectedSize) { REQUIRE((int)buffer.size() == expectedSize); - REQUIRE(((size_t)buffer.data() & (sfz::SIMDConfig::defaultAlignment - 1)) == 0); - REQUIRE(((size_t)buffer.alignedEnd() & (sfz::SIMDConfig::defaultAlignment - 1)) == 0); + REQUIRE(((size_t)buffer.data() & (sfz::config::defaultAlignment - 1)) == 0); + REQUIRE(((size_t)buffer.alignedEnd() & (sfz::config::defaultAlignment - 1)) == 0); REQUIRE(std::distance(buffer.begin(), buffer.end()) == expectedSize); REQUIRE(std::distance(buffer.begin(), buffer.alignedEnd()) >= expectedSize); } From 91435249c034c1ecf5db0c7341f05e86490e42fd Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 30 May 2020 15:05:18 +0200 Subject: [PATCH 02/42] Added base support for runtime config --- src/sfizz/SIMDHelpers.cpp | 51 +++++++++++++++++++++++++++++++++++++++ src/sfizz/SIMDHelpers.h | 33 +++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 src/sfizz/SIMDHelpers.cpp diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp new file mode 100644 index 00000000..b3081621 --- /dev/null +++ b/src/sfizz/SIMDHelpers.cpp @@ -0,0 +1,51 @@ +#include "SIMDHelpers.h" +#include + +namespace sfz{ + +static std::array(sfz::SIMDOps::_sentinel)> simdStatus; +static bool simdStatusInitialized = false; + +static void resetSIMDStatus() +{ + simdStatus[static_cast(SIMDOps::writeInterleaved)] = true; + simdStatus[static_cast(SIMDOps::readInterleaved)] = true; + simdStatus[static_cast(SIMDOps::fill)] = true; + simdStatus[static_cast(SIMDOps::gain)] = false; + simdStatus[static_cast(SIMDOps::divide)] = false; + simdStatus[static_cast(SIMDOps::mathfuns)] = false; + simdStatus[static_cast(SIMDOps::loopingSFZIndex)] = true; + simdStatus[static_cast(SIMDOps::saturatingSFZIndex)] = true; + simdStatus[static_cast(SIMDOps::linearRamp)] = false; + simdStatus[static_cast(SIMDOps::multiplicativeRamp)] = true; + simdStatus[static_cast(SIMDOps::add)] = false; + simdStatus[static_cast(SIMDOps::subtract)] = false; + simdStatus[static_cast(SIMDOps::multiplyAdd)] = false; + simdStatus[static_cast(SIMDOps::copy)] = false; + simdStatus[static_cast(SIMDOps::pan)] = false; + simdStatus[static_cast(SIMDOps::cumsum)] = true; + simdStatus[static_cast(SIMDOps::diff)] = false; + simdStatus[static_cast(SIMDOps::sfzInterpolationCast)] = true; + simdStatus[static_cast(SIMDOps::mean)] = false; + simdStatus[static_cast(SIMDOps::meanSquared)] = false; + simdStatus[static_cast(SIMDOps::upsampling)] = true; + simdStatusInitialized = true; +} + +static void setSIMDOpStatus(SIMDOps op, bool status) +{ + if (!simdStatusInitialized) + resetSIMDStatus(); + + simdStatus[static_cast(op)] = status; +} +static bool getSIMDOpStatus(SIMDOps op) +{ + if (!simdStatusInitialized) + resetSIMDStatus(); + + return simdStatus[static_cast(op)]; +} + +} + diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index 0600ddd6..732d615c 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -41,6 +41,39 @@ #include namespace sfz { + +// NOTE: The goal is to collapse all checks on release, and compute the sentinels for the span versions +// https://godbolt.org/z/43dveW shows this should work + +enum class SIMDOps { + writeInterleaved, + readInterleaved, + fill, + gain, + divide, + mathfuns, + loopingSFZIndex, + saturatingSFZIndex, + linearRamp, + multiplicativeRamp, + add, + subtract, + multiplyAdd, + copy, + pan, + cumsum, + diff, + sfzInterpolationCast, + mean, + meanSquared, + upsampling, + _sentinel // +}; +// Enable or disable SIMD accelerators at runtime +static void setSIMDOpStatus(SIMDOps op, bool status); +static bool getSIMDOpStatus(SIMDOps op); + + namespace _internals { template inline void snippetRead(const T*& input, T*& outputLeft, T*& outputRight) From f827e7c2e5ef4700b5eddee9368fb98084d56ea8 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 30 May 2020 20:11:27 +0200 Subject: [PATCH 03/42] Update the read and write SIMD helpers with the new approach --- cmake/SfizzSIMDSourceFiles.cmake | 1 + src/sfizz/FilePool.cpp | 5 +- src/sfizz/SIMDHelpers.cpp | 99 ++++++++++++++++++++++++++-- src/sfizz/SIMDHelpers.h | 82 +++++++++++------------ src/sfizz/SIMDSSE.cpp | 109 +------------------------------ tests/SIMDHelpersT.cpp | 47 ++++++++----- 6 files changed, 168 insertions(+), 175 deletions(-) diff --git a/cmake/SfizzSIMDSourceFiles.cmake b/cmake/SfizzSIMDSourceFiles.cmake index ef0e1d1b..962d0fb0 100644 --- a/cmake/SfizzSIMDSourceFiles.cmake +++ b/cmake/SfizzSIMDSourceFiles.cmake @@ -3,6 +3,7 @@ macro(sfizz_add_simd_sources SOURCES_VAR PREFIX) list (APPEND ${SOURCES_VAR} ${PREFIX}/sfizz/SIMDSSE.cpp + ${PREFIX}/sfizz/SIMDHelpers.cpp ${PREFIX}/sfizz/SIMDNEON.cpp ${PREFIX}/sfizz/SIMDDummy.cpp) diff --git a/src/sfizz/FilePool.cpp b/src/sfizz/FilePool.cpp index 04f33cc9..95519ac6 100644 --- a/src/sfizz/FilePool.cpp +++ b/src/sfizz/FilePool.cpp @@ -60,7 +60,7 @@ void readBaseFile(SndfileHandle& sndFile, sfz::FileAudioBuffer& output, uint32_t output.clear(); sfz::Buffer tempReadBuffer { 2 * numFrames }; sndFile.readf(tempReadBuffer.data(), numFrames); - sfz::readInterleaved(tempReadBuffer, output.getSpan(0), output.getSpan(1)); + sfz::readInterleaved(tempReadBuffer, output.getSpan(0), output.getSpan(1)); } if (reverse) { @@ -87,7 +87,6 @@ std::unique_ptr readFromFile(SndfileHandle& sndFile, uint3 return outputBuffer; } -template void streamFromFile(SndfileHandle& sndFile, uint32_t numFrames, sfz::Oversampling factor, bool reverse, sfz::FileAudioBuffer& output, std::atomic* filledFrames = nullptr) { if (factor == sfz::Oversampling::x1) { @@ -400,7 +399,7 @@ void sfz::FilePool::loadingThread() noexcept continue; } const auto frames = static_cast(sndFile.frames()); - streamFromFile(sndFile, frames, oversamplingFactor, promise->fileId.isReverse(), promise->fileData, &promise->availableFrames); + streamFromFile(sndFile, frames, oversamplingFactor, promise->fileId.isReverse(), promise->fileData, &promise->availableFrames); promise->dataStatus = FilePromise::DataStatus::Ready; const auto loadDuration = std::chrono::high_resolution_clock::now() - loadStartTime; logger.logFileTime(waitDuration, loadDuration, frames, promise->fileId.filename()); diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index b3081621..5308f601 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -1,12 +1,20 @@ #include "SIMDHelpers.h" #include +#include "cpuid/cpuinfo.hpp" -namespace sfz{ +#include "SIMDConfig.h" -static std::array(sfz::SIMDOps::_sentinel)> simdStatus; +#if SFIZZ_HAVE_SSE2 +#include +#include +#endif + +namespace sfz { + +static std::array(SIMDOps::_sentinel)> simdStatus; static bool simdStatusInitialized = false; -static void resetSIMDStatus() +void resetSIMDStatus() { simdStatus[static_cast(SIMDOps::writeInterleaved)] = true; simdStatus[static_cast(SIMDOps::readInterleaved)] = true; @@ -32,14 +40,15 @@ static void resetSIMDStatus() simdStatusInitialized = true; } -static void setSIMDOpStatus(SIMDOps op, bool status) +void setSIMDOpStatus(SIMDOps op, bool status) { if (!simdStatusInitialized) resetSIMDStatus(); simdStatus[static_cast(op)] = status; } -static bool getSIMDOpStatus(SIMDOps op) + +bool getSIMDOpStatus(SIMDOps op) { if (!simdStatusInitialized) resetSIMDStatus(); @@ -47,5 +56,85 @@ static bool getSIMDOpStatus(SIMDOps op) return simdStatus[static_cast(op)]; } +constexpr uintptr_t TypeAlignment = 4; + +template +inline void tickRead(const T*& input, T*& outputLeft, T*& outputRight) +{ + *outputLeft++ = *input++; + *outputRight++ = *input++; +} + +template +inline void tickWrite(T*& output, const T*& inputLeft, const T*& inputRight) +{ + *output++ = *inputLeft++; + *output++ = *inputRight++; +} + +void readInterleaved(const float* input, float* outputLeft, float* outputRight, unsigned inputSize) noexcept +{ + const auto sentinel = input + inputSize - 1; + cpuid::cpuinfo cpuInfo; + if (getSIMDOpStatus(SIMDOps::readInterleaved)) { +#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 + if (cpuInfo.has_sse()) { + const auto* lastAligned = prevAligned(input + inputSize - 4); + while (unaligned(input, outputLeft, outputRight) && input < lastAligned) + tickRead(input, outputLeft, outputRight); + + while (input < lastAligned) { + auto register0 = _mm_load_ps(input); + auto register1 = _mm_load_ps(input + 4); + auto register2 = register0; + // register 2 holds the copy of register 0 that is going to get erased by the first operation + // Remember that the bit mask reads from the end; 10 00 10 00 means + // "take 0 from a, take 2 from a, take 0 from b, take 2 from b" + register0 = _mm_shuffle_ps(register0, register1, 0b10001000); + register1 = _mm_shuffle_ps(register2, register1, 0b11011101); + _mm_store_ps(outputLeft, register0); + _mm_store_ps(outputRight, register1); + incrementAll<4>(input, input, outputLeft, outputRight); + } + // Fallthrough from lastAligned to sentinel + } +#endif + } + + while (input < sentinel) + tickRead(input, outputLeft, outputRight); +} + +void writeInterleaved(const float* inputLeft, const float* inputRight, float* output, unsigned outputSize) noexcept +{ + const auto sentinel = output + outputSize - 1; + + cpuid::cpuinfo cpuInfo; + if (getSIMDOpStatus(SIMDOps::readInterleaved)) { +#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 + if (cpuInfo.has_sse()) { + const auto* lastAligned = prevAligned(output + outputSize - 4); + + while (unaligned(output, inputRight, inputLeft) && output < lastAligned) + tickWrite(output, inputLeft, inputRight); + + while (output < lastAligned) { + const auto lInRegister = _mm_load_ps(inputLeft); + const auto rInRegister = _mm_load_ps(inputRight); + const auto outRegister1 = _mm_unpacklo_ps(lInRegister, rInRegister); + _mm_store_ps(output, outRegister1); + const auto outRegister2 = _mm_unpackhi_ps(lInRegister, rInRegister); + _mm_store_ps(output + 4, outRegister2); + incrementAll<4>(output, output, inputLeft, inputRight); + } + // fallthrough from lastAligned to sentinel + } +#endif + } + + while (output < sentinel) + tickWrite(output, inputLeft, inputRight); +} + } diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index 732d615c..5bce8a78 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -69,18 +69,35 @@ enum class SIMDOps { upsampling, _sentinel // }; + // Enable or disable SIMD accelerators at runtime -static void setSIMDOpStatus(SIMDOps op, bool status); -static bool getSIMDOpStatus(SIMDOps op); +void setSIMDOpStatus(SIMDOps op, bool status); +bool getSIMDOpStatus(SIMDOps op); +constexpr uintptr_t ByteAlignmentMask { config::defaultAlignment - 1 }; -namespace _internals { - template - inline void snippetRead(const T*& input, T*& outputLeft, T*& outputRight) - { - *outputLeft++ = *input++; - *outputRight++ = *input++; - } +template +T* nextAligned(const T* ptr) +{ + return reinterpret_cast(reinterpret_cast(ptr) + ByteAlignmentMask & (~ByteAlignmentMask)); +} + +template +T* prevAligned(const T* ptr) +{ + return reinterpret_cast(reinterpret_cast(ptr) & (~ByteAlignmentMask)); +} + +template +bool unaligned(const T* ptr) +{ + return (reinterpret_cast(ptr) & ByteAlignmentMask )!= 0; +} + +template +bool unaligned(const T* ptr1, Args... rest) +{ + return unaligned(ptr1) || unaligned(rest...); } /** @@ -89,33 +106,21 @@ namespace _internals { * The output size will be the minimum of the input span and output spans size. * * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version * @param input * @param outputLeft * @param outputRight */ -template -void readInterleaved(absl::Span input, absl::Span outputLeft, absl::Span outputRight) noexcept +void readInterleaved(const float* input, float* outputLeft, float* outputRight, unsigned inputSize) noexcept; + +inline void readInterleaved(absl::Span input, absl::Span outputLeft, absl::Span outputRight) noexcept { // The size of the output is not big enough for the input... CHECK(outputLeft.size() >= input.size() / 2); CHECK(outputRight.size() >= input.size() / 2); - - auto* in = input.begin(); - auto* lOut = outputLeft.begin(); - auto* rOut = outputRight.begin(); - while (in < (input.end() - 1) && lOut < outputLeft.end() && rOut < outputRight.end()) - _internals::snippetRead(in, lOut, rOut); + const auto size = min(input.size(), 2 * outputLeft.size(), 2 * outputRight.size()); + readInterleaved(input.data(), outputLeft.data(), outputRight.data(), size); } -namespace _internals { - template - inline void snippetWrite(T*& output, const T*& inputLeft, const T*& inputRight) - { - *output++ = *inputLeft++; - *output++ = *inputRight++; - } -} /** * @brief Write a pair of left and right stereo input into a single buffer interleaved. @@ -123,30 +128,21 @@ namespace _internals { * The output size will be the minimum of the input spans and output span size. * * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version * @param inputLeft * @param inputRight * @param output */ -template -void writeInterleaved(absl::Span inputLeft, absl::Span inputRight, absl::Span output) noexcept +void writeInterleaved(const float* inputLeft, const float* inputRight, float* output, unsigned outputSize) noexcept; + +inline void writeInterleaved(absl::Span inputLeft, absl::Span inputRight, absl::Span output) noexcept { - CHECK(inputLeft.size() <= output.size() / 2); - CHECK(inputRight.size() <= output.size() / 2); - - auto* lIn = inputLeft.begin(); - auto* rIn = inputRight.begin(); - auto* out = output.begin(); - while (lIn < inputLeft.end() && rIn < inputRight.end() && out < (output.end() - 1)) - _internals::snippetWrite(out, lIn, rIn); + // Not enough data in the inputs + CHECK(inputLeft.size() >= output.size() / 2); + CHECK(inputRight.size() >= output.size() / 2); + const auto size = min(output.size(), 2 * inputLeft.size(), 2 * inputRight.size()); + writeInterleaved(inputLeft.data(), inputRight.data(), output.data(), size); } -// Specializations -template <> -void writeInterleaved(absl::Span inputLeft, absl::Span inputRight, absl::Span output) noexcept; -template <> -void readInterleaved(absl::Span input, absl::Span outputLeft, absl::Span outputRight) noexcept; - /** * @brief Fill a buffer with a value; comparable to std::fill in essence. * diff --git a/src/sfizz/SIMDSSE.cpp b/src/sfizz/SIMDSSE.cpp index ae0cd07e..b0dcf2d9 100644 --- a/src/sfizz/SIMDSSE.cpp +++ b/src/sfizz/SIMDSSE.cpp @@ -12,116 +12,9 @@ #include #include #include - #include "mathfuns/sse_mathfun.h" -using Type = float; -constexpr uintptr_t TypeAlignment { 4 }; -constexpr uintptr_t ByteAlignment { TypeAlignment * sizeof(Type) }; -constexpr uintptr_t ByteAlignmentMask { ByteAlignment - 1 }; - -struct AlignmentSentinels { - float* nextAligned; - float* lastAligned; -}; - -float* nextAligned(const float* ptr) -{ - return reinterpret_cast((reinterpret_cast(ptr) + ByteAlignmentMask) & (~ByteAlignmentMask)); -} - -float* prevAligned(const float* ptr) -{ - return reinterpret_cast(reinterpret_cast(ptr) & (~ByteAlignmentMask)); -} - -bool unaligned(const float* ptr) -{ - return (reinterpret_cast(ptr) & ByteAlignmentMask) != 0; -} - -template -bool unaligned(const float* ptr1, Args... rest) -{ - return unaligned(ptr1) || unaligned(rest...); -} - -template <> -void sfz::readInterleaved(absl::Span input, absl::Span outputLeft, absl::Span outputRight) noexcept -{ - // The size of the outputs is not big enough for the input... - CHECK(outputLeft.size() >= input.size() / 2); - CHECK(outputRight.size() >= input.size() / 2); - // Input is too small - CHECK(input.size() > 1); - - auto* in = input.begin(); - auto* lOut = outputLeft.begin(); - auto* rOut = outputRight.begin(); - - const auto size = std::min(input.size(), std::min(outputLeft.size() * 2, outputRight.size() * 2)); - const auto* lastAligned = prevAligned(input.begin() + size - TypeAlignment); - - while (unaligned(in, lOut, rOut) && in < lastAligned) - _internals::snippetRead(in, lOut, rOut); - - while (in < lastAligned) { - auto register0 = _mm_load_ps(in); - in += TypeAlignment; - auto register1 = _mm_load_ps(in); - in += TypeAlignment; - auto register2 = register0; - // register 2 holds the copy of register 0 that is going to get erased by the first operation - // Remember that the bit mask reads from the end; 10 00 10 00 means - // "take 0 from a, take 2 from a, take 0 from b, take 2 from b" - register0 = _mm_shuffle_ps(register0, register1, 0b10001000); - register1 = _mm_shuffle_ps(register2, register1, 0b11011101); - _mm_store_ps(lOut, register0); - _mm_store_ps(rOut, register1); - lOut += TypeAlignment; - rOut += TypeAlignment; - } - - while (in < input.end() - 1) - _internals::snippetRead(in, lOut, rOut); -} - -template <> -void sfz::writeInterleaved(absl::Span inputLeft, absl::Span inputRight, absl::Span output) noexcept -{ - // The size of the output is not big enough for the inputs... - CHECK(inputLeft.size() <= output.size() / 2); - CHECK(inputRight.size() <= output.size() / 2); - - auto* lIn = inputLeft.begin(); - auto* rIn = inputRight.begin(); - auto* out = output.begin(); - - const auto size = std::min(output.size(), std::min(inputLeft.size(), inputRight.size()) * 2); - const auto* lastAligned = prevAligned(output.begin() + size - TypeAlignment); - - while (unaligned(out, rIn, lIn) && out < lastAligned) - _internals::snippetWrite(out, lIn, rIn); - - while (out < lastAligned) { - const auto lInRegister = _mm_load_ps(lIn); - const auto rInRegister = _mm_load_ps(rIn); - - const auto outRegister1 = _mm_unpacklo_ps(lInRegister, rInRegister); - _mm_store_ps(out, outRegister1); - out += TypeAlignment; - - const auto outRegister2 = _mm_unpackhi_ps(lInRegister, rInRegister); - _mm_store_ps(out, outRegister2); - out += TypeAlignment; - - lIn += TypeAlignment; - rIn += TypeAlignment; - } - - while (out < output.end() - 1) - _internals::snippetWrite(out, lIn, rIn); -} +constexpr uintptr_t TypeAlignment = 4; template <> void sfz::fill(absl::Span output, float value) noexcept diff --git a/tests/SIMDHelpersT.cpp b/tests/SIMDHelpersT.cpp index 44c837c4..06133ef0 100644 --- a/tests/SIMDHelpersT.cpp +++ b/tests/SIMDHelpersT.cpp @@ -122,7 +122,8 @@ TEST_CASE("[Helpers] Interleaved read") std::array expected { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f }; std::array leftOutput; std::array rightOutput; - sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); + sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; auto realIdx = 0; @@ -139,7 +140,8 @@ TEST_CASE("[Helpers] Interleaved read unaligned end") std::array expected { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f }; std::array leftOutput; std::array rightOutput; - sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); + sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; auto realIdx = 0; @@ -156,7 +158,8 @@ TEST_CASE("[Helpers] Small interleaved read unaligned end") std::array expected { 0.0f, 1.0f, 2.0f, 10.0f, 11.0f, 12.0f }; std::array leftOutput; std::array rightOutput; - sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); + sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; auto realIdx = 0; @@ -173,7 +176,8 @@ TEST_CASE("[Helpers] Interleaved read -- SIMD") std::array expected = { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f }; std::array leftOutput; std::array rightOutput; - sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); + sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; auto realIdx = 0; @@ -190,7 +194,8 @@ TEST_CASE("[Helpers] Interleaved read unaligned end -- SIMD") std::array expected = { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f }; std::array leftOutput; std::array rightOutput; - sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); + sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; auto realIdx = 0; @@ -207,7 +212,8 @@ TEST_CASE("[Helpers] Small interleaved read unaligned end -- SIMD") std::array expected { 0.0f, 1.0f, 2.0f, 10.0f, 11.0f, 12.0f }; std::array leftOutput; std::array rightOutput; - sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); + sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; auto realIdx = 0; @@ -226,8 +232,10 @@ TEST_CASE("[Helpers] Interleaved read SIMD vs Scalar") std::array leftOutputSIMD; std::array rightOutputSIMD; std::iota(input.begin(), input.end(), 0.0f); - sfz::readInterleaved(input, absl::MakeSpan(leftOutputScalar), absl::MakeSpan(rightOutputScalar)); - sfz::readInterleaved(input, absl::MakeSpan(leftOutputSIMD), absl::MakeSpan(rightOutputSIMD)); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); + sfz::readInterleaved(input, absl::MakeSpan(leftOutputScalar), absl::MakeSpan(rightOutputScalar)); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); + sfz::readInterleaved(input, absl::MakeSpan(leftOutputSIMD), absl::MakeSpan(rightOutputSIMD)); REQUIRE(leftOutputScalar == leftOutputSIMD); REQUIRE(rightOutputScalar == rightOutputSIMD); } @@ -247,7 +255,8 @@ TEST_CASE("[Helpers] Interleaved write") std::array rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f }; std::array output; std::array expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f }; - sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); + sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -257,7 +266,8 @@ TEST_CASE("[Helpers] Interleaved write unaligned end") std::array rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f }; std::array output; std::array expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f, 8.0f, 18.0f, 9.0f, 19.0f }; - sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); + sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -267,7 +277,8 @@ TEST_CASE("[Helpers] Small interleaved write unaligned end") std::array rightInput { 10.0f, 11.0f, 12.0f }; std::array output; std::array expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f }; - sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); + sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -286,7 +297,8 @@ TEST_CASE("[Helpers] Interleaved write -- SIMD") std::array rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f }; std::array output; std::array expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f }; - sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true); + sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -296,7 +308,7 @@ TEST_CASE("[Helpers] Interleaved write unaligned end -- SIMD") std::array rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f }; std::array output; std::array expected = { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f, 8.0f, 18.0f, 9.0f, 19.0f }; - sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); + sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -306,7 +318,8 @@ TEST_CASE("[Helpers] Small interleaved write unaligned end -- SIMD") std::array rightInput { 10.0f, 11.0f, 12.0f }; std::array output; std::array expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f }; - sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true); + sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -318,8 +331,10 @@ TEST_CASE("[Helpers] Interleaved write SIMD vs Scalar") std::array outputSIMD; std::iota(leftInput.begin(), leftInput.end(), 0.0f); std::iota(rightInput.begin(), rightInput.end(), static_cast(medBufferSize)); - sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(outputScalar)); - sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(outputSIMD)); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); + sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(outputScalar)); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true); + sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(outputSIMD)); REQUIRE(outputScalar == outputSIMD); } From b74e376e1645ad371a56c20496bd35d4f9b3e05b Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 30 May 2020 20:27:44 +0200 Subject: [PATCH 04/42] Update the benchmarks --- benchmarks/BM_readInterleaved.cpp | 34 +++++++++++++++++++++----- benchmarks/BM_writeInterleaved.cpp | 39 +++++++++++++++++++++--------- benchmarks/CMakeLists.txt | 2 +- 3 files changed, 57 insertions(+), 18 deletions(-) diff --git a/benchmarks/BM_readInterleaved.cpp b/benchmarks/BM_readInterleaved.cpp index 65bfcc8d..2255e98f 100644 --- a/benchmarks/BM_readInterleaved.cpp +++ b/benchmarks/BM_readInterleaved.cpp @@ -18,7 +18,8 @@ static void Scalar(benchmark::State& state) { std::iota(input.begin(), input.end(), 1.0f); for (auto _ : state) { - sfz::readInterleaved(input, absl::MakeSpan(outputLeft), absl::MakeSpan(outputRight)); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); + sfz::readInterleaved(input, absl::MakeSpan(outputLeft), absl::MakeSpan(outputRight)); } } @@ -29,7 +30,8 @@ static void SSE(benchmark::State& state) { std::iota(input.begin(), input.end(), 1.0f); for (auto _ : state) { - sfz::readInterleaved(input, absl::MakeSpan(outputLeft), absl::MakeSpan(outputRight)); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); + sfz::readInterleaved(input, absl::MakeSpan(outputLeft), absl::MakeSpan(outputRight)); } } @@ -39,7 +41,12 @@ static void Scalar_Unaligned(benchmark::State& state) { sfz::Buffer outputRight (state.range(0)); std::iota(input.begin(), input.end(), 1.0f); for (auto _ : state) { - sfz::readInterleaved(absl::MakeSpan(input).subspan(2), absl::MakeSpan(outputLeft), absl::MakeSpan(outputRight)); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); + sfz::readInterleaved( + absl::MakeSpan(input).subspan(2), + absl::MakeSpan(outputLeft), + absl::MakeSpan(outputRight) + ); } } @@ -49,7 +56,12 @@ static void SSE_Unaligned(benchmark::State& state) { sfz::Buffer outputRight (state.range(0)); std::iota(input.begin(), input.end(), 1.0f); for (auto _ : state) { - sfz::readInterleaved(absl::MakeSpan(input).subspan(2), absl::MakeSpan(outputLeft), absl::MakeSpan(outputRight)); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); + sfz::readInterleaved( + absl::MakeSpan(input).subspan(2), + absl::MakeSpan(outputLeft), + absl::MakeSpan(outputRight) + ); } } @@ -59,7 +71,12 @@ static void Scalar_Unaligned_2(benchmark::State& state) { sfz::Buffer outputRight (state.range(0)); std::iota(input.begin(), input.end(), 1.0f); for (auto _ : state) { - sfz::readInterleaved(absl::MakeSpan(input).subspan(2), absl::MakeSpan(outputLeft).subspan(1), absl::MakeSpan(outputRight).subspan(3)); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); + sfz::readInterleaved( + absl::MakeSpan(input).subspan(2), + absl::MakeSpan(outputLeft).subspan(1), + absl::MakeSpan(outputRight).subspan(3) + ); } } @@ -69,7 +86,12 @@ static void SSE_Unaligned_2(benchmark::State& state) { sfz::Buffer outputRight (state.range(0)); std::iota(input.begin(), input.end(), 1.0f); for (auto _ : state) { - sfz::readInterleaved(absl::MakeSpan(input).subspan(2), absl::MakeSpan(outputLeft).subspan(1), absl::MakeSpan(outputRight).subspan(3)); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); + sfz::readInterleaved( + absl::MakeSpan(input).subspan(2), + absl::MakeSpan(outputLeft).subspan(1), + absl::MakeSpan(outputRight).subspan(3) + ); } } diff --git a/benchmarks/BM_writeInterleaved.cpp b/benchmarks/BM_writeInterleaved.cpp index e22f3d7f..f7612fa9 100644 --- a/benchmarks/BM_writeInterleaved.cpp +++ b/benchmarks/BM_writeInterleaved.cpp @@ -19,7 +19,8 @@ static void Interleaved_Write(benchmark::State& state) { std::iota(inputRight.begin(), inputRight.end(), 1.0f); for (auto _ : state) { - sfz::writeInterleaved(inputLeft, inputRight, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); + sfz::writeInterleaved(inputLeft, inputRight, absl::MakeSpan(output)); } } @@ -30,8 +31,8 @@ static void Interleaved_Write_SSE(benchmark::State& state) { std::iota(inputLeft.begin(), inputLeft.end(), 1.0f); std::iota(inputRight.begin(), inputRight.end(), 1.0f); for (auto _ : state) { - sfz::writeInterleaved(inputLeft, inputRight, absl::MakeSpan(output)); - benchmark::DoNotOptimize(output); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true); + sfz::writeInterleaved(inputLeft, inputRight, absl::MakeSpan(output)); } } @@ -42,8 +43,12 @@ static void Unaligned_Interleaved_Write(benchmark::State& state) { std::iota(inputLeft.begin(), inputLeft.end(), 1.0f); std::iota(inputRight.begin(), inputRight.end(), 1.0f); for (auto _ : state) { - sfz::writeInterleaved(absl::MakeSpan(inputLeft).subspan(1) , absl::MakeSpan(inputRight).subspan(1), absl::MakeSpan(output).subspan(2)); - benchmark::DoNotOptimize(output); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); + sfz::writeInterleaved( + absl::MakeSpan(inputLeft).subspan(1), + absl::MakeSpan(inputRight).subspan(1), + absl::MakeSpan(output).subspan(2) + ); } } @@ -54,8 +59,12 @@ static void Unaligned_Interleaved_Write_SSE(benchmark::State& state) { std::iota(inputLeft.begin(), inputLeft.end(), 1.0f); std::iota(inputRight.begin(), inputRight.end(), 1.0f); for (auto _ : state) { - sfz::writeInterleaved(absl::MakeSpan(inputLeft).subspan(1) , absl::MakeSpan(inputRight).subspan(1), absl::MakeSpan(output).subspan(2)); - benchmark::DoNotOptimize(output); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true); + sfz::writeInterleaved( + absl::MakeSpan(inputLeft).subspan(1), + absl::MakeSpan(inputRight).subspan(1), + absl::MakeSpan(output).subspan(2) + ); } } @@ -66,8 +75,12 @@ static void Unaligned_Interleaved_Write_2(benchmark::State& state) { std::iota(inputLeft.begin(), inputLeft.end(), 1.0f); std::iota(inputRight.begin(), inputRight.end(), 1.0f); for (auto _ : state) { - sfz::writeInterleaved(absl::MakeSpan(inputLeft) , absl::MakeSpan(inputRight).subspan(1), absl::MakeSpan(output).subspan(2)); - benchmark::DoNotOptimize(output); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); + sfz::writeInterleaved( + absl::MakeSpan(inputLeft), + absl::MakeSpan(inputRight).subspan(1), + absl::MakeSpan(output).subspan(2) + ); } } @@ -78,8 +91,12 @@ static void Unaligned_Interleaved_Write_SSE_2(benchmark::State& state) { std::iota(inputLeft.begin(), inputLeft.end(), 1.0f); std::iota(inputRight.begin(), inputRight.end(), 1.0f); for (auto _ : state) { - sfz::writeInterleaved(absl::MakeSpan(inputLeft) , absl::MakeSpan(inputRight).subspan(1), absl::MakeSpan(output).subspan(2)); - benchmark::DoNotOptimize(output); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true); + sfz::writeInterleaved( + absl::MakeSpan(inputLeft), + absl::MakeSpan(inputRight).subspan(1), + absl::MakeSpan(output).subspan(2) + ); } } diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 53aa801a..adf8d001 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -18,7 +18,7 @@ if(SAMPLERATE_LIBRARY AND SAMPLERATE_INCLUDE_DIR) endif() add_library(bm_simd STATIC ${BENCHMARK_SIMD_SOURCES}) -target_link_libraries(bm_simd PRIVATE absl::span) +target_link_libraries(bm_simd PRIVATE absl::span sfizz-cpuid) target_include_directories(bm_simd PRIVATE ../src/external) add_library(bm_ftz STATIC ../src/sfizz/ScopedFTZ.cpp) From 6e811f92b234f01ccdb7846e75cd231a194bef43 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 30 May 2020 20:41:25 +0200 Subject: [PATCH 05/42] Alignment helpers for possibly any sizes --- src/sfizz/SIMDHelpers.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index 5bce8a78..b8915297 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -74,30 +74,30 @@ enum class SIMDOps { void setSIMDOpStatus(SIMDOps op, bool status); bool getSIMDOpStatus(SIMDOps op); -constexpr uintptr_t ByteAlignmentMask { config::defaultAlignment - 1 }; +constexpr uintptr_t ByteAlignmentMask(unsigned N) { return N - 1; } -template +template T* nextAligned(const T* ptr) { - return reinterpret_cast(reinterpret_cast(ptr) + ByteAlignmentMask & (~ByteAlignmentMask)); + return reinterpret_cast(reinterpret_cast(ptr) + ByteAlignmentMask(N) & (~ByteAlignmentMask(N))); } -template +template T* prevAligned(const T* ptr) { - return reinterpret_cast(reinterpret_cast(ptr) & (~ByteAlignmentMask)); + return reinterpret_cast(reinterpret_cast(ptr) & (~ByteAlignmentMask(N))); } -template +template bool unaligned(const T* ptr) { - return (reinterpret_cast(ptr) & ByteAlignmentMask )!= 0; + return (reinterpret_cast(ptr) & ByteAlignmentMask(N) )!= 0; } -template +template bool unaligned(const T* ptr1, Args... rest) { - return unaligned(ptr1) || unaligned(rest...); + return unaligned(ptr1) || unaligned(rest...); } /** From 78191327d7e6b3c1a7c1352dfe4bc7cfa0055b02 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 30 May 2020 20:53:35 +0200 Subject: [PATCH 06/42] Remove the fill benchmark --- benchmarks/BM_fill.cpp | 70 --------------------------------------- benchmarks/CMakeLists.txt | 1 - 2 files changed, 71 deletions(-) delete mode 100644 benchmarks/BM_fill.cpp diff --git a/benchmarks/BM_fill.cpp b/benchmarks/BM_fill.cpp deleted file mode 100644 index 86e0e7cf..00000000 --- a/benchmarks/BM_fill.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause - -// This code is part of the sfizz library and is licensed under a BSD 2-clause -// license. You should have receive a LICENSE.md file along with the code. -// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz - -#include "SIMDHelpers.h" -#include -#include "Buffer.h" -#include -#include -#include - -static void Dummy(benchmark::State& state) { - sfz::Buffer buffer (state.range(0)); - std::random_device rd { }; - std::mt19937 gen { rd() }; - std::uniform_real_distribution dist { 1, 2 }; - for (auto _ : state) { - auto fillValue = dist(gen); - benchmark::DoNotOptimize(fillValue); - } -} - -static void FillScalar(benchmark::State& state) { - sfz::Buffer buffer (state.range(0)); - std::random_device rd { }; - std::mt19937 gen { rd() }; - std::uniform_real_distribution dist { 1, 2 }; - for (auto _ : state) { - sfz::fill(absl::MakeSpan(buffer), dist(gen)); - } -} - -static void FillScalar_unaligned(benchmark::State& state) { - sfz::Buffer buffer (state.range(0)); - std::random_device rd { }; - std::mt19937 gen { rd() }; - std::uniform_real_distribution dist { 1, 2 }; - for (auto _ : state) { - sfz::fill(absl::MakeSpan(buffer).subspan(1), dist(gen)); - } -} - -static void FillSIMD(benchmark::State& state) { - sfz::Buffer buffer (state.range(0)); - std::random_device rd { }; - std::mt19937 gen { rd() }; - std::uniform_real_distribution dist { 1, 2 }; - for (auto _ : state) { - sfz::fill(absl::MakeSpan(buffer), dist(gen)); - } -} - -static void FillSIMD_unaligned(benchmark::State& state) { - sfz::Buffer buffer (state.range(0)); - std::random_device rd { }; - std::mt19937 gen { rd() }; - std::uniform_real_distribution dist { 1, 2 }; - for (auto _ : state) { - sfz::fill(absl::MakeSpan(buffer).subspan(1), dist(gen)); - } -} - -BENCHMARK(Dummy)->RangeMultiplier(4)->Range((1<<2), (1<<12)); -BENCHMARK(FillScalar)->RangeMultiplier(4)->Range((1<<2), (1<<12)); -BENCHMARK(FillSIMD)->RangeMultiplier(4)->Range((1<<2), (1<<12)); -BENCHMARK(FillScalar_unaligned)->RangeMultiplier(4)->Range((1<<2), (1<<12)); -BENCHMARK(FillSIMD_unaligned)->RangeMultiplier(4)->Range((1<<2), (1<<12)); -BENCHMARK_MAIN(); diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index adf8d001..3f3ca5b2 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -38,7 +38,6 @@ sfizz_add_benchmark(bm_opf_high_vs_low BM_OPF_high_vs_low.cpp) sfizz_add_benchmark(bm_clock BM_clock.cpp) sfizz_add_benchmark(bm_write BM_writeInterleaved.cpp) sfizz_add_benchmark(bm_read BM_readInterleaved.cpp) -sfizz_add_benchmark(bm_fill BM_fill.cpp) sfizz_add_benchmark(bm_mathfuns BM_mathfuns.cpp) sfizz_add_benchmark(bm_gain BM_gain.cpp) sfizz_add_benchmark(bm_divide BM_divide.cpp) From 781cae65ef8aa5806d534444145e3cf12fd2f7eb Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 30 May 2020 20:53:49 +0200 Subject: [PATCH 07/42] Remove the fill tests --- tests/SIMDHelpersT.cpp | 68 ------------------------------------------ 1 file changed, 68 deletions(-) diff --git a/tests/SIMDHelpersT.cpp b/tests/SIMDHelpersT.cpp index 06133ef0..8bf3eed4 100644 --- a/tests/SIMDHelpersT.cpp +++ b/tests/SIMDHelpersT.cpp @@ -48,74 +48,6 @@ inline bool approxEqual(absl::Span lhs, absl::Span rhs, return true; } -TEST_CASE("[Helpers] fill() - Manual buffer") -{ - std::vector buffer(5); - std::vector expected { fillValue, fillValue, fillValue, fillValue, fillValue }; - sfz::fill(absl::MakeSpan(buffer), fillValue); - REQUIRE(buffer == expected); -} - -TEST_CASE("[Helpers] fill() - Small buffer") -{ - std::vector buffer(smallBufferSize); - std::vector expected(smallBufferSize); - std::fill(expected.begin(), expected.end(), fillValue); - - sfz::fill(absl::MakeSpan(buffer), fillValue); - REQUIRE(buffer == expected); -} - -TEST_CASE("[Helpers] fill() - Big buffer") -{ - std::vector buffer(bigBufferSize); - std::vector expected(bigBufferSize); - std::fill(expected.begin(), expected.end(), fillValue); - - sfz::fill(absl::MakeSpan(buffer), fillValue); - REQUIRE(buffer == expected); -} - -TEST_CASE("[Helpers] fill() - Small buffer -- SIMD") -{ - std::vector buffer(smallBufferSize); - std::vector expected(smallBufferSize); - std::fill(expected.begin(), expected.end(), fillValue); - - sfz::fill(absl::MakeSpan(buffer), fillValue); - REQUIRE(buffer == expected); -} - -TEST_CASE("[Helpers] fill() - Big buffer -- SIMD") -{ - std::vector buffer(bigBufferSize); - std::vector expected(bigBufferSize); - std::fill(expected.begin(), expected.end(), fillValue); - - sfz::fill(absl::MakeSpan(buffer), fillValue); - REQUIRE(buffer == expected); -} - -TEST_CASE("[Helpers] fill() - Small buffer -- doubles") -{ - std::vector buffer(smallBufferSize); - std::vector expected(smallBufferSize); - std::fill(expected.begin(), expected.end(), fillValue); - - sfz::fill(absl::MakeSpan(buffer), fillValue); - REQUIRE(buffer == expected); -} - -TEST_CASE("[Helpers] fill() - Big buffer -- doubles") -{ - std::vector buffer(bigBufferSize); - std::vector expected(bigBufferSize); - std::fill(expected.begin(), expected.end(), fillValue); - - sfz::fill(absl::MakeSpan(buffer), fillValue); - REQUIRE(buffer == expected); -} - TEST_CASE("[Helpers] Interleaved read") { std::array input { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f }; From b10b05078a209b7ae1908f2048308c61f88b95bb Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 30 May 2020 20:59:41 +0200 Subject: [PATCH 08/42] The fill simd helper is just an alias for absl::c_fill The pass-by-value alias is still necessary for cases where you pass an rvalue to the function (which happens often when e.g. you take a subspan) --- benchmarks/BM_pan.cpp | 2 +- src/sfizz/AudioSpan.h | 2 +- src/sfizz/HistoricalBuffer.h | 2 +- src/sfizz/ModifierHelpers.h | 16 ++++++++-------- src/sfizz/SIMDHelpers.h | 5 +---- src/sfizz/SIMDSSE.cpp | 20 -------------------- src/sfizz/Voice.cpp | 12 ++++++------ 7 files changed, 18 insertions(+), 41 deletions(-) diff --git a/benchmarks/BM_pan.cpp b/benchmarks/BM_pan.cpp index 8cafb079..70707ee9 100644 --- a/benchmarks/BM_pan.cpp +++ b/benchmarks/BM_pan.cpp @@ -67,7 +67,7 @@ BENCHMARK_DEFINE_F(PanArray, BlockOps)(benchmark::State& state) { ScopedFTZ ftz; for (auto _ : state) { - sfz::fill(span2, 1.0f); + sfz::fill(span2, 1.0f); sfz::add(span1, span2); sfz::applyGain(piFour(), span2); sfz::cos(span2, span1); diff --git a/src/sfizz/AudioSpan.h b/src/sfizz/AudioSpan.h index 23c9d340..21fcb4be 100644 --- a/src/sfizz/AudioSpan.h +++ b/src/sfizz/AudioSpan.h @@ -279,7 +279,7 @@ public: { static_assert(!std::is_const::value, "Can't allow mutating operations on const AudioSpans"); for (size_t i = 0; i < numChannels; ++i) - sfz::fill(getSpan(i), value); + sfz::fill(getSpan(i), value); } /** diff --git a/src/sfizz/HistoricalBuffer.h b/src/sfizz/HistoricalBuffer.h index e2b3b8e5..a52b8932 100644 --- a/src/sfizz/HistoricalBuffer.h +++ b/src/sfizz/HistoricalBuffer.h @@ -35,7 +35,7 @@ public: void resize(size_t size) { buffer.resize(size); - fill(absl::MakeSpan(buffer), 0.0); + fill(absl::MakeSpan(buffer), ValueType { 0 }); index = 0; validMean = false; } diff --git a/src/sfizz/ModifierHelpers.h b/src/sfizz/ModifierHelpers.h index 8e01610a..e3d8006e 100644 --- a/src/sfizz/ModifierHelpers.h +++ b/src/sfizz/ModifierHelpers.h @@ -74,7 +74,7 @@ void linearEnvelope(const EventVector& events, absl::Span envelope, F&& l lastValue = linearRamp(envelope.subspan(lastDelay, length), lastValue, step); lastDelay += length; } - fill(envelope.subspan(lastDelay), lastValue); + fill(envelope.subspan(lastDelay), lastValue); } template @@ -100,7 +100,7 @@ void linearEnvelope(const EventVector& events, absl::Span envelope, F&& l const auto length = min(events[i].delay, maxDelay) - lastDelay; if (difference < step) { - fill(envelope.subspan(lastDelay, length), lastValue); + fill(envelope.subspan(lastDelay, length), lastValue); lastValue = nextValue; lastDelay += length; continue; @@ -109,12 +109,12 @@ void linearEnvelope(const EventVector& events, absl::Span envelope, F&& l const auto numSteps = static_cast(difference / step); const auto stepLength = static_cast(length / numSteps); for (int i = 0; i < numSteps; ++i) { - fill(envelope.subspan(lastDelay, stepLength), lastValue); + fill(envelope.subspan(lastDelay, stepLength), lastValue); lastValue += lastValue <= nextValue ? step : -step; lastDelay += stepLength; } } - fill(envelope.subspan(lastDelay), lastValue); + fill(envelope.subspan(lastDelay), lastValue); } template @@ -137,7 +137,7 @@ void multiplicativeEnvelope(const EventVector& events, absl::Span envelop lastValue = nextValue; lastDelay += length; } - fill(envelope.subspan(lastDelay), lastValue); + fill(envelope.subspan(lastDelay), lastValue); } template @@ -170,7 +170,7 @@ void multiplicativeEnvelope(const EventVector& events, absl::Span envelop const auto difference = nextValue > lastValue ? nextValue / lastValue : lastValue / nextValue; if (difference < step) { - fill(envelope.subspan(lastDelay, length), lastValue); + fill(envelope.subspan(lastDelay, length), lastValue); lastValue = nextValue; lastDelay += length; continue; @@ -179,12 +179,12 @@ void multiplicativeEnvelope(const EventVector& events, absl::Span envelop const auto numSteps = std::round(std::log(difference) / logStep); const auto stepLength = static_cast(length / numSteps); for (int i = 0; i < static_cast(numSteps); ++i) { - fill(envelope.subspan(lastDelay, stepLength), lastValue); + fill(envelope.subspan(lastDelay, stepLength), lastValue); lastValue = nextValue > lastValue ? lastValue * step : lastValue / step; lastDelay += stepLength; } } - fill(envelope.subspan(lastDelay), lastValue); + fill(envelope.subspan(lastDelay), lastValue); } template diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index b8915297..d22ef484 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -151,15 +151,12 @@ inline void writeInterleaved(absl::Span inputLeft, absl::Span +template void fill(absl::Span output, T value) noexcept { absl::c_fill(output, value); } -template <> -void fill(absl::Span output, float value) noexcept; - /** * @brief Exp math function * diff --git a/src/sfizz/SIMDSSE.cpp b/src/sfizz/SIMDSSE.cpp index b0dcf2d9..3c9fdb8f 100644 --- a/src/sfizz/SIMDSSE.cpp +++ b/src/sfizz/SIMDSSE.cpp @@ -16,26 +16,6 @@ constexpr uintptr_t TypeAlignment = 4; -template <> -void sfz::fill(absl::Span output, float value) noexcept -{ - const auto mmValue = _mm_set_ps1(value); - auto* out = output.begin(); - const auto* lastAligned = prevAligned(output.end()); - - while (unaligned(out) && out < lastAligned) - *out++ = value; - - while (out < lastAligned) // we should only need to test a single channel - { - _mm_store_ps(out, mmValue); - out += TypeAlignment; - } - - while (out < output.end()) - *out++ = value; -} - template <> void sfz::exp(absl::Span input, absl::Span output) noexcept { diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 98509af6..adca60c1 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -358,7 +358,7 @@ void sfz::Voice::panStageMono(AudioSpan buffer) noexcept copy(leftBuffer, rightBuffer); // Apply panning - fill(*modulationSpan, region->pan); + fill(*modulationSpan, region->pan); for (const auto& mod : region->panCC) { linearModifier(resources, *tempSpan, mod, normalizePercents); add(*tempSpan, *modulationSpan); @@ -379,7 +379,7 @@ void sfz::Voice::panStageStereo(AudioSpan buffer) noexcept return; // Apply panning - fill(*modulationSpan, region->pan); + fill(*modulationSpan, region->pan); for (const auto& mod : region->panCC) { linearModifier(resources, *tempSpan, mod, normalizePercents); add(*tempSpan, *modulationSpan); @@ -387,14 +387,14 @@ void sfz::Voice::panStageStereo(AudioSpan buffer) noexcept pan(*modulationSpan, leftBuffer, rightBuffer); // Apply the width/position process - fill(*modulationSpan, region->width); + fill(*modulationSpan, region->width); for (const auto& mod : region->widthCC) { linearModifier(resources, *tempSpan, mod, normalizePercents); add(*tempSpan, *modulationSpan); } width(*modulationSpan, leftBuffer, rightBuffer); - fill(*modulationSpan, region->position); + fill(*modulationSpan, region->position); for (const auto& mod : region->positionCC) { linearModifier(resources, *tempSpan, mod, normalizePercents); add(*tempSpan, *modulationSpan); @@ -457,7 +457,7 @@ void sfz::Voice::fillWithData(AudioSpan buffer) noexcept if (!jumps || !bends || !indices || !coeffs) return; - fill(*jumps, pitchRatio * speedRatio); + fill(*jumps, pitchRatio * speedRatio); const auto events = resources.midiState.getPitchEvents(); const auto bendLambda = [this](float bend) { @@ -588,7 +588,7 @@ void sfz::Voice::fillWithGenerator(AudioSpan buffer) noexcept return; float keycenterFrequency = midiNoteFrequency(region->pitchKeycenter); - fill(*frequencies, pitchRatio * keycenterFrequency); + fill(*frequencies, pitchRatio * keycenterFrequency); const auto events = resources.midiState.getPitchEvents(); const auto bendLambda = [this](float bend) { From 04af0b8d80c43a8a010b6a8d9dd1d0da5d478dc1 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 30 May 2020 21:18:20 +0200 Subject: [PATCH 09/42] Remove the trig/log/exp functions We're tabulating these if speed is needed anyway --- benchmarks/BM_mathfuns.cpp | 100 -------------------------------- benchmarks/BM_pan.cpp | 15 ----- benchmarks/BM_ramp.cpp | 61 ------------------- benchmarks/BM_readChunk.cpp | 8 +-- benchmarks/BM_readChunkFlac.cpp | 6 +- benchmarks/BM_resample.cpp | 32 +++++----- benchmarks/BM_resampleChunk.cpp | 6 +- benchmarks/CMakeLists.txt | 2 +- src/sfizz/SIMDHelpers.h | 97 +------------------------------ src/sfizz/SIMDSSE.cpp | 84 --------------------------- tests/EQ.cpp | 2 +- tests/Filter.cpp | 2 +- 12 files changed, 32 insertions(+), 383 deletions(-) diff --git a/benchmarks/BM_mathfuns.cpp b/benchmarks/BM_mathfuns.cpp index aa11b966..6cf78e9a 100644 --- a/benchmarks/BM_mathfuns.cpp +++ b/benchmarks/BM_mathfuns.cpp @@ -45,96 +45,6 @@ BENCHMARK_DEFINE_F(MyFixture, Dummy) } } -BENCHMARK_DEFINE_F(MyFixture, ScalarExp) -(benchmark::State& state) -{ - for (auto _ : state) { - sfz::exp(source, absl::MakeSpan(result)); - benchmark::DoNotOptimize(result); - } -} - -BENCHMARK_DEFINE_F(MyFixture, SIMDExp) -(benchmark::State& state) -{ - for (auto _ : state) { - sfz::exp(source, absl::MakeSpan(result)); - benchmark::DoNotOptimize(result); - } -} - -BENCHMARK_DEFINE_F(MyFixture, ScalarExp_Unaligned) -(benchmark::State& state) -{ - for (auto _ : state) { - sfz::exp(absl::MakeSpan(source).subspan(1), absl::MakeSpan(result).subspan(1)); - benchmark::DoNotOptimize(result); - } -} - -BENCHMARK_DEFINE_F(MyFixture, SIMDExp_Unaligned) -(benchmark::State& state) -{ - for (auto _ : state) { - sfz::exp(absl::MakeSpan(source).subspan(1), absl::MakeSpan(result).subspan(1)); - benchmark::DoNotOptimize(result); - } -} - -BENCHMARK_DEFINE_F(MyFixture, ScalarLog) -(benchmark::State& state) -{ - for (auto _ : state) { - sfz::log(source, absl::MakeSpan(result)); - benchmark::DoNotOptimize(result); - } -} - -BENCHMARK_DEFINE_F(MyFixture, SIMDLog) -(benchmark::State& state) -{ - for (auto _ : state) { - sfz::log(source, absl::MakeSpan(result)); - benchmark::DoNotOptimize(result); - } -} - -BENCHMARK_DEFINE_F(MyFixture, ScalarSin) -(benchmark::State& state) -{ - for (auto _ : state) { - sfz::sin(source, absl::MakeSpan(result)); - benchmark::DoNotOptimize(result); - } -} - -BENCHMARK_DEFINE_F(MyFixture, SIMDSin) -(benchmark::State& state) -{ - for (auto _ : state) { - sfz::sin(source, absl::MakeSpan(result)); - benchmark::DoNotOptimize(result); - } -} - -BENCHMARK_DEFINE_F(MyFixture, ScalarCos) -(benchmark::State& state) -{ - for (auto _ : state) { - sfz::cos(source, absl::MakeSpan(result)); - benchmark::DoNotOptimize(result); - } -} - -BENCHMARK_DEFINE_F(MyFixture, SIMDCos) -(benchmark::State& state) -{ - for (auto _ : state) { - sfz::cos(source, absl::MakeSpan(result)); - benchmark::DoNotOptimize(result); - } -} - BENCHMARK_DEFINE_F(MyFixture, ScalarLibmFloorLog2) (benchmark::State& state) { @@ -159,16 +69,6 @@ BENCHMARK_DEFINE_F(MyFixture, ScalarFastFloorLog2) } BENCHMARK_REGISTER_F(MyFixture, Dummy)->RangeMultiplier(4)->Range(1 << 6, 1 << 10); -BENCHMARK_REGISTER_F(MyFixture, ScalarExp)->RangeMultiplier(4)->Range(1 << 6, 1 << 10); -BENCHMARK_REGISTER_F(MyFixture, SIMDExp)->RangeMultiplier(4)->Range(1 << 6, 1 << 10); -BENCHMARK_REGISTER_F(MyFixture, ScalarExp_Unaligned)->RangeMultiplier(4)->Range(1 << 6, 1 << 10); -BENCHMARK_REGISTER_F(MyFixture, SIMDExp_Unaligned)->RangeMultiplier(4)->Range(1 << 6, 1 << 10); -BENCHMARK_REGISTER_F(MyFixture, ScalarLog)->RangeMultiplier(4)->Range(1 << 6, 1 << 10); -BENCHMARK_REGISTER_F(MyFixture, SIMDLog)->RangeMultiplier(4)->Range(1 << 6, 1 << 10); -BENCHMARK_REGISTER_F(MyFixture, ScalarSin)->RangeMultiplier(4)->Range(1 << 6, 1 << 10); -BENCHMARK_REGISTER_F(MyFixture, SIMDSin)->RangeMultiplier(4)->Range(1 << 6, 1 << 10); -BENCHMARK_REGISTER_F(MyFixture, ScalarCos)->RangeMultiplier(4)->Range(1 << 6, 1 << 10); -BENCHMARK_REGISTER_F(MyFixture, SIMDCos)->RangeMultiplier(4)->Range(1 << 6, 1 << 10); BENCHMARK_REGISTER_F(MyFixture, ScalarLibmFloorLog2)->RangeMultiplier(4)->Range(1 << 6, 1 << 10); BENCHMARK_REGISTER_F(MyFixture, ScalarFastFloorLog2)->RangeMultiplier(4)->Range(1 << 6, 1 << 10); diff --git a/benchmarks/BM_pan.cpp b/benchmarks/BM_pan.cpp index 70707ee9..e08b447e 100644 --- a/benchmarks/BM_pan.cpp +++ b/benchmarks/BM_pan.cpp @@ -63,21 +63,6 @@ BENCHMARK_DEFINE_F(PanArray, SIMD)(benchmark::State& state) { } } -BENCHMARK_DEFINE_F(PanArray, BlockOps)(benchmark::State& state) { - ScopedFTZ ftz; - for (auto _ : state) - { - sfz::fill(span2, 1.0f); - sfz::add(span1, span2); - sfz::applyGain(piFour(), span2); - sfz::cos(span2, span1); - sfz::sin(span2, span2); - sfz::applyGain(span1, absl::MakeSpan(left)); - sfz::applyGain(span2, absl::MakeSpan(right)); - } -} - BENCHMARK_REGISTER_F(PanArray, Scalar)->RangeMultiplier(4)->Range(1 << 2, 1 << 12); BENCHMARK_REGISTER_F(PanArray, SIMD)->RangeMultiplier(4)->Range(1 << 2, 1 << 12); -BENCHMARK_REGISTER_F(PanArray, BlockOps)->RangeMultiplier(4)->Range(1 << 2, 1 << 12); BENCHMARK_MAIN(); diff --git a/benchmarks/BM_ramp.cpp b/benchmarks/BM_ramp.cpp index 3d7ee14e..2a056392 100644 --- a/benchmarks/BM_ramp.cpp +++ b/benchmarks/BM_ramp.cpp @@ -116,63 +116,6 @@ static void MulSIMDUnaligned(benchmark::State& state) { } } -static void LogDomainScalar(benchmark::State& state) { - sfz::Buffer output(state.range(0)); - std::random_device rd { }; - std::mt19937 gen { rd() }; - std::uniform_real_distribution dist { 1, 2 }; - for (auto _ : state) - { - auto value = dist(gen); - sfz::linearRamp(absl::MakeSpan(output), 1.0f, value); - sfz::applyGain(std::log(2.0f), absl::MakeSpan(output)); - sfz::exp(output, absl::MakeSpan(output)); - } -} - -static void LogDomainSIMD(benchmark::State& state) { - sfz::Buffer output(state.range(0)); - std::random_device rd { }; - std::mt19937 gen { rd() }; - std::uniform_real_distribution dist { 1, 2 }; - for (auto _ : state) - { - auto value = dist(gen); - sfz::linearRamp(absl::MakeSpan(output), 1.0f, value); - sfz::applyGain(std::log(2.0f), absl::MakeSpan(output)); - sfz::exp(output, absl::MakeSpan(output)); - } -} -static void LogDomainScalarUnaligned(benchmark::State& state) { - sfz::Buffer output(state.range(0)); - std::random_device rd { }; - std::mt19937 gen { rd() }; - std::uniform_real_distribution dist { 1, 2 }; - for (auto _ : state) - { - auto value = dist(gen); - auto outputSpan = absl::MakeSpan(output).subspan(1); - sfz::linearRamp(outputSpan, 1.0f, value); - sfz::applyGain(std::log(2.0f), outputSpan); - sfz::exp(outputSpan, outputSpan); - } -} - -static void LogDomainSIMDUnaligned(benchmark::State& state) { - sfz::Buffer output(state.range(0)); - std::random_device rd { }; - std::mt19937 gen { rd() }; - std::uniform_real_distribution dist { 1, 2 }; - for (auto _ : state) - { - auto value = dist(gen); - auto outputSpan = absl::MakeSpan(output).subspan(1); - sfz::linearRamp(outputSpan, 1.0f, value); - sfz::applyGain(std::log(2.0f), outputSpan); - sfz::exp(outputSpan, outputSpan); - } -} - // Register the function as a benchmark BENCHMARK(Dummy)->RangeMultiplier(4)->Range((1 << 2), (1 << 12)); BENCHMARK(LinearScalar)->RangeMultiplier(4)->Range((1 << 2), (1 << 12)); @@ -183,8 +126,4 @@ BENCHMARK(MulScalar)->RangeMultiplier(4)->Range((1 << 2), (1 << 12)); BENCHMARK(MulSIMD)->RangeMultiplier(4)->Range((1 << 2), (1 << 12)); BENCHMARK(MulScalarUnaligned)->RangeMultiplier(4)->Range((1 << 2), (1 << 12)); BENCHMARK(MulSIMDUnaligned)->RangeMultiplier(4)->Range((1 << 2), (1 << 12)); -BENCHMARK(LogDomainScalar)->RangeMultiplier(4)->Range((1 << 2), (1 << 12)); -BENCHMARK(LogDomainSIMD)->RangeMultiplier(4)->Range((1 << 2), (1 << 12)); -BENCHMARK(LogDomainScalarUnaligned)->RangeMultiplier(4)->Range((1 << 2), (1 << 12)); -BENCHMARK(LogDomainSIMDUnaligned)->RangeMultiplier(4)->Range((1 << 2), (1 << 12)); BENCHMARK_MAIN(); diff --git a/benchmarks/BM_readChunk.cpp b/benchmarks/BM_readChunk.cpp index 4cdc2068..01b93aaa 100644 --- a/benchmarks/BM_readChunk.cpp +++ b/benchmarks/BM_readChunk.cpp @@ -61,7 +61,7 @@ BENCHMARK_DEFINE_F(FileFixture, JustRead)(benchmark::State& state) { { sfz::Buffer buffer { numFrames * sndfile.channels() }; sndfile.readf(buffer.data(), numFrames); - sfz::readInterleaved(buffer, output->getSpan(0), output->getSpan(1)); + sfz::readInterleaved(buffer, output->getSpan(0), output->getSpan(1)); } } @@ -75,7 +75,7 @@ BENCHMARK_DEFINE_F(FileFixture, AllocInside)(benchmark::State& state) { { sfz::Buffer buffer { chunkSize * sndfile.channels() }; auto read = sndfile.readf(buffer.data(), chunkSize); - sfz::readInterleaved( + sfz::readInterleaved( absl::MakeSpan(buffer).first(read), output->getSpan(0).subspan(framesRead), output->getSpan(1).subspan(framesRead) @@ -95,7 +95,7 @@ BENCHMARK_DEFINE_F(FileFixture, AllocOutside)(benchmark::State& state) { while(framesRead < numFrames) { auto read = sndfile.readf(buffer.data(), chunkSize); - sfz::readInterleaved( + sfz::readInterleaved( absl::MakeSpan(buffer).first(read), output->getSpan(0).subspan(framesRead), output->getSpan(1).subspan(framesRead) @@ -124,7 +124,7 @@ BENCHMARK_DEFINE_F(FileFixture, DrWavChunked)(benchmark::State& state) { while(framesRead < numFrames) { auto read = drwav_read_pcm_frames_f32(&wav, chunkSize, buffer.data()); - sfz::readInterleaved( + sfz::readInterleaved( absl::MakeSpan(buffer).first(read), output->getSpan(0).subspan(framesRead), output->getSpan(1).subspan(framesRead) diff --git a/benchmarks/BM_readChunkFlac.cpp b/benchmarks/BM_readChunkFlac.cpp index 048ae23d..df77f637 100644 --- a/benchmarks/BM_readChunkFlac.cpp +++ b/benchmarks/BM_readChunkFlac.cpp @@ -61,7 +61,7 @@ BENCHMARK_DEFINE_F(FileFixture, SndFileOnce)(benchmark::State& state) { { sfz::Buffer buffer { numFrames * sndfile.channels() }; sndfile.readf(buffer.data(), numFrames); - sfz::readInterleaved(buffer, output->getSpan(0), output->getSpan(1)); + sfz::readInterleaved(buffer, output->getSpan(0), output->getSpan(1)); } } @@ -75,7 +75,7 @@ BENCHMARK_DEFINE_F(FileFixture, SndFileChunked)(benchmark::State& state) { { sfz::Buffer buffer { chunkSize * sndfile.channels() }; auto read = sndfile.readf(buffer.data(), chunkSize); - sfz::readInterleaved( + sfz::readInterleaved( absl::MakeSpan(buffer).first(read), output->getSpan(0).subspan(framesRead), output->getSpan(1).subspan(framesRead) @@ -104,7 +104,7 @@ BENCHMARK_DEFINE_F(FileFixture, DrWavChunked)(benchmark::State& state) { while(framesRead < numFrames) { auto read = drflac_read_pcm_frames_f32(flac, chunkSize, buffer.data()); - sfz::readInterleaved( + sfz::readInterleaved( absl::MakeSpan(buffer).first(read), output->getSpan(0).subspan(framesRead), output->getSpan(1).subspan(framesRead) diff --git a/benchmarks/BM_resample.cpp b/benchmarks/BM_resample.cpp index 75101ac3..ffd7f902 100644 --- a/benchmarks/BM_resample.cpp +++ b/benchmarks/BM_resample.cpp @@ -232,7 +232,7 @@ BENCHMARK_DEFINE_F(SndFile, HIIR2X_scalar)(benchmark::State& state) { for (auto _ : state) { auto baseBuffer = absl::make_unique>(numChannels, numFrames); - sfz::readInterleaved(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1)); + sfz::readInterleaved(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1)); auto outBuffer = upsample2x(*baseBuffer); benchmark::DoNotOptimize(outBuffer); } @@ -242,7 +242,7 @@ BENCHMARK_DEFINE_F(SndFile, HIIR4X_scalar)(benchmark::State& state) { for (auto _ : state) { auto baseBuffer = absl::make_unique>(numChannels, numFrames); - sfz::readInterleaved(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1)); + sfz::readInterleaved(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1)); auto outBuffer = upsample4x(*baseBuffer); benchmark::DoNotOptimize(outBuffer); } @@ -252,7 +252,7 @@ BENCHMARK_DEFINE_F(SndFile, HIIR8X_scalar)(benchmark::State& state) { for (auto _ : state) { auto baseBuffer = absl::make_unique>(numChannels, numFrames); - sfz::readInterleaved(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1)); + sfz::readInterleaved(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1)); auto outBuffer = upsample8x(*baseBuffer); benchmark::DoNotOptimize(outBuffer); } @@ -262,7 +262,7 @@ BENCHMARK_DEFINE_F(SndFile, HIIR2X_vector)(benchmark::State& state) { for (auto _ : state) { auto baseBuffer = absl::make_unique>(numChannels, numFrames); - sfz::readInterleaved(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1)); + sfz::readInterleaved(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1)); auto outBuffer = upsample2x(*baseBuffer); benchmark::DoNotOptimize(outBuffer); } @@ -272,7 +272,7 @@ BENCHMARK_DEFINE_F(SndFile, HIIR4X_vector)(benchmark::State& state) { for (auto _ : state) { auto baseBuffer = absl::make_unique>(numChannels, numFrames); - sfz::readInterleaved(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1)); + sfz::readInterleaved(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1)); auto outBuffer = upsample4x(*baseBuffer); benchmark::DoNotOptimize(outBuffer); } @@ -282,7 +282,7 @@ BENCHMARK_DEFINE_F(SndFile, HIIR8X_vector)(benchmark::State& state) { for (auto _ : state) { auto baseBuffer = absl::make_unique>(numChannels, numFrames); - sfz::readInterleaved(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1)); + sfz::readInterleaved(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1)); auto outBuffer = upsample8x(*baseBuffer); benchmark::DoNotOptimize(outBuffer); } @@ -300,7 +300,7 @@ BENCHMARK_DEFINE_F(SndFile, SRC2x_BEST)(benchmark::State& state) srcData.output_frames = static_cast(2 * numFrames); src_simple(&srcData, SRC_SINC_BEST_QUALITY, static_cast(numChannels)); auto outBuffer = absl::make_unique>(numChannels, 2 * numFrames); - sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1)); + sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1)); benchmark::DoNotOptimize(outBuffer); } } @@ -317,7 +317,7 @@ BENCHMARK_DEFINE_F(SndFile, SRC2x_MEDIUM)(benchmark::State& state) srcData.output_frames = static_cast(2 * numFrames); src_simple(&srcData, SRC_SINC_MEDIUM_QUALITY, static_cast(numChannels)); auto outBuffer = absl::make_unique>(numChannels, 2 * numFrames); - sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1)); + sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1)); benchmark::DoNotOptimize(outBuffer); } } @@ -334,7 +334,7 @@ BENCHMARK_DEFINE_F(SndFile, SRC2x_FASTEST)(benchmark::State& state) srcData.output_frames = static_cast(2 * numFrames); src_simple(&srcData, SRC_SINC_FASTEST, static_cast(numChannels)); auto outBuffer = absl::make_unique>(numChannels, 2 * numFrames); - sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1)); + sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1)); benchmark::DoNotOptimize(outBuffer); } } @@ -352,7 +352,7 @@ BENCHMARK_DEFINE_F(SndFile, SRC4x_BEST)(benchmark::State& state) srcData.output_frames = static_cast(2 * numFrames); src_simple(&srcData, SRC_SINC_BEST_QUALITY, static_cast(numChannels)); auto outBuffer = absl::make_unique>(numChannels, 2 * numFrames); - sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1)); + sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1)); benchmark::DoNotOptimize(outBuffer); } } @@ -369,7 +369,7 @@ BENCHMARK_DEFINE_F(SndFile, SRC4x_MEDIUM)(benchmark::State& state) srcData.output_frames = static_cast(2 * numFrames); src_simple(&srcData, SRC_SINC_MEDIUM_QUALITY, static_cast(numChannels)); auto outBuffer = absl::make_unique>(numChannels, 2 * numFrames); - sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1)); + sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1)); benchmark::DoNotOptimize(outBuffer); } } @@ -386,7 +386,7 @@ BENCHMARK_DEFINE_F(SndFile, SRC4x_FASTEST)(benchmark::State& state) srcData.output_frames = static_cast(2 * numFrames); src_simple(&srcData, SRC_SINC_FASTEST, static_cast(numChannels)); auto outBuffer = absl::make_unique>(numChannels, 2 * numFrames); - sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1)); + sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1)); benchmark::DoNotOptimize(outBuffer); } } @@ -403,7 +403,7 @@ BENCHMARK_DEFINE_F(SndFile, SRC8x_BEST)(benchmark::State& state) srcData.output_frames = static_cast(2 * numFrames); src_simple(&srcData, SRC_SINC_BEST_QUALITY, static_cast(numChannels)); auto outBuffer = absl::make_unique>(numChannels, 2 * numFrames); - sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1)); + sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1)); benchmark::DoNotOptimize(outBuffer); } } @@ -420,7 +420,7 @@ BENCHMARK_DEFINE_F(SndFile, SRC8x_MEDIUM)(benchmark::State& state) srcData.output_frames = static_cast(2 * numFrames); src_simple(&srcData, SRC_SINC_MEDIUM_QUALITY, static_cast(numChannels)); auto outBuffer = absl::make_unique>(numChannels, 2 * numFrames); - sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1)); + sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1)); benchmark::DoNotOptimize(outBuffer); } } @@ -437,7 +437,7 @@ BENCHMARK_DEFINE_F(SndFile, SRC8x_FASTEST)(benchmark::State& state) srcData.output_frames = static_cast(2 * numFrames); src_simple(&srcData, SRC_SINC_FASTEST, static_cast(numChannels)); auto outBuffer = absl::make_unique>(numChannels, 2 * numFrames); - sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1)); + sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1)); benchmark::DoNotOptimize(outBuffer); } } @@ -446,7 +446,7 @@ BENCHMARK_DEFINE_F(SndFile, HIIR8X_default)(benchmark::State& state) { for (auto _ : state) { auto baseBuffer = absl::make_unique>(numChannels, numFrames); - sfz::readInterleaved(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1)); + sfz::readInterleaved(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1)); auto outBuffer = upsample8x(*baseBuffer); benchmark::DoNotOptimize(outBuffer); } diff --git a/benchmarks/BM_resampleChunk.cpp b/benchmarks/BM_resampleChunk.cpp index a75c06c5..59ba3434 100644 --- a/benchmarks/BM_resampleChunk.cpp +++ b/benchmarks/BM_resampleChunk.cpp @@ -105,7 +105,7 @@ BENCHMARK_DEFINE_F(FileFixture, NoResampling)(benchmark::State& state) { { sfz::Buffer buffer { numFrames * sndfile.channels() }; sndfile.readf(buffer.data(), sndfile.frames()); - sfz::readInterleaved(buffer, output->getSpan(0), output->getSpan(1)); + sfz::readInterleaved(buffer, output->getSpan(0), output->getSpan(1)); } } @@ -121,7 +121,7 @@ BENCHMARK_DEFINE_F(FileFixture, ResampleAtOnce)(benchmark::State& state) { upsampler4x.set_coefs(coeffsStage4x.data()); sndfile.readf(buffer.data(), numFrames); - sfz::readInterleaved(buffer, output->getSpan(0), output->getSpan(1)); + sfz::readInterleaved(buffer, output->getSpan(0), output->getSpan(1)); upsampler2x.process_block(temp.data(), output->channelReader(0), static_cast(numFrames)); upsampler4x.process_block(output->channelWriter(0), temp.data(), static_cast(numFrames * 2)); @@ -171,7 +171,7 @@ BENCHMARK_DEFINE_F(FileFixture, ResampleInChunks)(benchmark::State& state) { thisChunkSize * sndfile.channels() ); - sfz::readInterleaved(bufferChunk, leftSpan, rightSpan); + sfz::readInterleaved(bufferChunk, leftSpan, rightSpan); upsampler2xLeft.process_block(chunkSpan.data(), leftSpan.data(), static_cast(thisChunkSize)); upsampler4xLeft.process_block(output->channelWriter(0) + outputFrameCounter, chunkSpan.data(), static_cast(thisChunkSize * 2)); diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 3f3ca5b2..b2fa4195 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -70,7 +70,7 @@ target_link_libraries(bm_logger PRIVATE sfizz::sfizz) if (TARGET sfizz-samplerate) sfizz_add_benchmark(bm_resample BM_resample.cpp ${BENCHMARK_SIMD_SOURCES}) -target_link_libraries(bm_resample PRIVATE sfizz-samplerate sfizz-sndfile) +target_link_libraries(bm_resample PRIVATE sfizz-samplerate sfizz-sndfile sfizz-cpuid) endif() sfizz_add_benchmark(bm_envelopes BM_envelopes.cpp) diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index d22ef484..840853a3 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -103,12 +103,10 @@ bool unaligned(const T* ptr1, Args... rest) /** * @brief Read interleaved stereo data from a buffer and separate it in a left/right pair of buffers. * - * The output size will be the minimum of the input span and output spans size. - * - * @tparam T the underlying type * @param input * @param outputLeft * @param outputRight + * @param inputSize */ void readInterleaved(const float* input, float* outputLeft, float* outputRight, unsigned inputSize) noexcept; @@ -125,12 +123,10 @@ inline void readInterleaved(absl::Span input, absl::Span out /** * @brief Write a pair of left and right stereo input into a single buffer interleaved. * - * The output size will be the minimum of the input spans and output span size. - * - * @tparam T the underlying type * @param inputLeft * @param inputRight * @param output + * @param outputSize */ void writeInterleaved(const float* inputLeft, const float* inputRight, float* output, unsigned outputSize) noexcept; @@ -144,10 +140,9 @@ inline void writeInterleaved(absl::Span inputLeft, absl::Span output, T value) noexcept absl::c_fill(output, value); } -/** - * @brief Exp math function - * - * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version - * @param input - * @param output - */ -template -void exp(absl::Span input, absl::Span output) noexcept -{ - CHECK(output.size() >= input.size()); - auto sentinel = std::min(input.size(), output.size()); - for (decltype(sentinel) i = 0; i < sentinel; ++i) - output[i] = std::exp(input[i]); -} - -template <> -void exp(absl::Span input, absl::Span output) noexcept; - -/** - * @brief Log math function - * - * The output size will be the minimum of the input span and output span size. - * - * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version - * @param input - * @param output - */ -template -void log(absl::Span input, absl::Span output) noexcept -{ - CHECK(output.size() >= input.size()); - auto sentinel = std::min(input.size(), output.size()); - for (decltype(sentinel) i = 0; i < sentinel; ++i) - output[i] = std::log(input[i]); -} - -template <> -void log(absl::Span input, absl::Span output) noexcept; - -/** - * @brief sin math function - * - * The output size will be the minimum of the input span and output span size. - * - * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version - * @param input - * @param output - */ -template -void sin(absl::Span input, absl::Span output) noexcept -{ - CHECK(output.size() >= input.size()); - auto sentinel = std::min(input.size(), output.size()); - for (decltype(sentinel) i = 0; i < sentinel; ++i) - output[i] = std::sin(input[i]); -} - -template <> -void sin(absl::Span input, absl::Span output) noexcept; - -/** - * @brief cos math function - * - * The output size will be the minimum of the input span and output span size. - * - * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version - * @param input - * @param output - */ -template -void cos(absl::Span input, absl::Span output) noexcept -{ - CHECK(output.size() >= input.size()); - auto sentinel = std::min(input.size(), output.size()); - for (decltype(sentinel) i = 0; i < sentinel; ++i) - output[i] = std::cos(input[i]); -} - -template <> -void cos(absl::Span input, absl::Span output) noexcept; - namespace _internals { template inline void snippetSaturatingIndex(const T*& jump, T*& leftCoeff, T*& rightCoeff, int*& index, T& floatIndex, T loopEnd) diff --git a/src/sfizz/SIMDSSE.cpp b/src/sfizz/SIMDSSE.cpp index 3c9fdb8f..607ae2e7 100644 --- a/src/sfizz/SIMDSSE.cpp +++ b/src/sfizz/SIMDSSE.cpp @@ -16,90 +16,6 @@ constexpr uintptr_t TypeAlignment = 4; -template <> -void sfz::exp(absl::Span input, absl::Span output) noexcept -{ - CHECK(output.size() >= input.size()); - auto* in = input.begin(); - auto* out = output.begin(); - auto* sentinel = in + std::min(input.size(), output.size()); - const auto* lastAligned = prevAligned(sentinel); - - while (unaligned(in, out) && in < lastAligned) - *out++ = std::exp(*in++); - - while (in < lastAligned) { - _mm_store_ps(out, exp_ps(_mm_load_ps(in))); - incrementAll(out, in); - } - - while (in < sentinel) - *out++ = std::exp(*in++); -} - -template <> -void sfz::cos(absl::Span input, absl::Span output) noexcept -{ - CHECK(output.size() >= input.size()); - auto* in = input.begin(); - auto* out = output.begin(); - auto* sentinel = in + std::min(input.size(), output.size()); - const auto* lastAligned = prevAligned(sentinel); - - while (unaligned(in, out) && in < lastAligned) - *out++ = std::exp(*in++); - - while (in < lastAligned) { - _mm_store_ps(out, cos_ps(_mm_load_ps(in))); - incrementAll(out, in); - } - - while (in < sentinel) - *out++ = std::exp(*in++); -} - -template <> -void sfz::log(absl::Span input, absl::Span output) noexcept -{ - CHECK(output.size() >= input.size()); - auto* in = input.begin(); - auto* out = output.begin(); - auto* sentinel = in + std::min(input.size(), output.size()); - const auto* lastAligned = prevAligned(sentinel); - - while (unaligned(in, out) && in < lastAligned) - *out++ = std::exp(*in++); - - while (in < lastAligned) { - _mm_store_ps(out, log_ps(_mm_load_ps(in))); - incrementAll(out, in); - } - - while (in < sentinel) - *out++ = std::exp(*in++); -} - -template <> -void sfz::sin(absl::Span input, absl::Span output) noexcept -{ - CHECK(output.size() >= input.size()); - auto* in = input.begin(); - auto* out = output.begin(); - auto* sentinel = in + std::min(input.size(), output.size()); - const auto* lastAligned = prevAligned(sentinel); - - while (unaligned(in, out) && in < lastAligned) - *out++ = std::exp(*in++); - - while (in < lastAligned) { - _mm_store_ps(out, sin_ps(_mm_load_ps(in))); - incrementAll(out, in); - } - - while (in < sentinel) - *out++ = std::exp(*in++); -} - template <> void sfz::applyGain(float gain, absl::Span input, absl::Span output) noexcept { diff --git a/tests/EQ.cpp b/tests/EQ.cpp index a75eea55..23082efe 100644 --- a/tests/EQ.cpp +++ b/tests/EQ.cpp @@ -68,7 +68,7 @@ int main(int argc, char** argv) sfz::Buffer buffer { numFrames * 2 }; sfz::Buffer right { numFrames }; sndfile.readf(buffer.data(), numFrames * 2 ); - sfz::readInterleaved(buffer, absl::MakeSpan(left), absl::MakeSpan(right)); + sfz::readInterleaved(buffer, absl::MakeSpan(left), absl::MakeSpan(right)); } else if (sndfile.channels() == 1) { sndfile.readf(left.data(), numFrames); } else { diff --git a/tests/Filter.cpp b/tests/Filter.cpp index 32c7bd2a..8104aa0b 100644 --- a/tests/Filter.cpp +++ b/tests/Filter.cpp @@ -71,7 +71,7 @@ int main(int argc, char** argv) sfz::Buffer buffer { numFrames * 2 }; sfz::Buffer right { numFrames }; sndfile.readf(buffer.data(), numFrames * 2 ); - sfz::readInterleaved(buffer, absl::MakeSpan(left), absl::MakeSpan(right)); + sfz::readInterleaved(buffer, absl::MakeSpan(left), absl::MakeSpan(right)); } else if (sndfile.channels() == 1) { sndfile.readf(left.data(), numFrames); } else { From 3c551d8f34c6ce0b3880f6d5de3fcfbae400f410 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 30 May 2020 21:25:30 +0200 Subject: [PATCH 10/42] Removed the now unused saturating and looping helpers --- benchmarks/BM_looping.cpp | 78 ------------------------ benchmarks/BM_saturating.cpp | 77 ----------------------- benchmarks/CMakeLists.txt | 2 - src/sfizz/SIMDHelpers.h | 114 ----------------------------------- src/sfizz/SIMDSSE.cpp | 114 ----------------------------------- tests/SIMDHelpersT.cpp | 99 ------------------------------ 6 files changed, 484 deletions(-) delete mode 100644 benchmarks/BM_looping.cpp delete mode 100644 benchmarks/BM_saturating.cpp diff --git a/benchmarks/BM_looping.cpp b/benchmarks/BM_looping.cpp deleted file mode 100644 index 6a465ffc..00000000 --- a/benchmarks/BM_looping.cpp +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause - -// This code is part of the sfizz library and is licensed under a BSD 2-clause -// license. You should have receive a LICENSE.md file along with the code. -// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz - -#include -#include "SIMDHelpers.h" -#include -#include -#include -#include - -// In this one we have an array of indices - -constexpr int loopStart { 5 }; -constexpr int loopEnd { 1076 }; -constexpr float maxJump { 4 }; - -class LoopingFixture : public benchmark::Fixture { -public: - void SetUp(const ::benchmark::State& state) { - std::random_device rd { }; - std::mt19937 gen { rd() }; - std::uniform_real_distribution dist { 0, maxJump }; - indices = std::vector(state.range(0)); - leftCoeffs = std::vector(state.range(0)); - rightCoeffs = std::vector(state.range(0)); - jumps = std::vector(state.range(0)); - absl::c_generate(jumps, [&]() { return dist(gen); }); - } - - void TearDown(const ::benchmark::State& /* state */) { - - } - - std::vector indices; - std::vector leftCoeffs; - std::vector rightCoeffs; - std::vector jumps; -}; - - -BENCHMARK_DEFINE_F(LoopingFixture, Scalar)(benchmark::State& state) { - for (auto _ : state) - { - sfz::loopingSFZIndex(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 2.5f, loopEnd, loopStart); - } -} - -BENCHMARK_DEFINE_F(LoopingFixture, SIMD)(benchmark::State& state) { - for (auto _ : state) - { - sfz::loopingSFZIndex(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 2.5f, loopEnd, loopStart); - } -} - -BENCHMARK_DEFINE_F(LoopingFixture, Scalar_Unaligned)(benchmark::State& state) { - for (auto _ : state) - { - sfz::loopingSFZIndex(absl::MakeSpan(jumps).subspan(1), absl::MakeSpan(leftCoeffs).subspan(2), absl::MakeSpan(rightCoeffs).subspan(1), absl::MakeSpan(indices).subspan(3), 2.5f, loopEnd, loopStart); - } -} - -BENCHMARK_DEFINE_F(LoopingFixture, SIMD_Unaligned)(benchmark::State& state) { - for (auto _ : state) - { - sfz::loopingSFZIndex(absl::MakeSpan(jumps).subspan(1), absl::MakeSpan(leftCoeffs).subspan(2), absl::MakeSpan(rightCoeffs).subspan(1), absl::MakeSpan(indices).subspan(3), 2.5f, loopEnd, loopStart); - } -} - - -// Register the function as a benchmark -BENCHMARK_REGISTER_F(LoopingFixture, Scalar)->RangeMultiplier(2)->Range((2<<6), (2<<12)); -BENCHMARK_REGISTER_F(LoopingFixture, SIMD)->RangeMultiplier(2)->Range((2<<6), (2<<12)); -BENCHMARK_REGISTER_F(LoopingFixture, Scalar_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12)); -BENCHMARK_REGISTER_F(LoopingFixture, SIMD_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12)); -BENCHMARK_MAIN(); diff --git a/benchmarks/BM_saturating.cpp b/benchmarks/BM_saturating.cpp deleted file mode 100644 index d6bb2427..00000000 --- a/benchmarks/BM_saturating.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause - -// This code is part of the sfizz library and is licensed under a BSD 2-clause -// license. You should have receive a LICENSE.md file along with the code. -// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz - -#include "SIMDHelpers.h" -#include -#include -#include -#include -#include - -// In this one we have an array of indices - -constexpr int loopEnd { 1076 }; -constexpr float maxJump { 4 }; - -class SaturatingFixture : public benchmark::Fixture { -public: - void SetUp(const ::benchmark::State& state) { - std::random_device rd { }; - std::mt19937 gen { rd() }; - std::uniform_real_distribution dist { 0, maxJump }; - indices = std::vector(state.range(0)); - leftCoeffs = std::vector(state.range(0)); - rightCoeffs = std::vector(state.range(0)); - jumps = std::vector(state.range(0)); - absl::c_generate(jumps, [&]() { return dist(gen); }); - } - - void TearDown(const ::benchmark::State& /* state */) { - - } - - std::vector indices; - std::vector leftCoeffs; - std::vector rightCoeffs; - std::vector jumps; -}; - - -BENCHMARK_DEFINE_F(SaturatingFixture, Scalar)(benchmark::State& state) { - for (auto _ : state) - { - sfz::saturatingSFZIndex(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 2.5f, loopEnd); - } -} - -BENCHMARK_DEFINE_F(SaturatingFixture, SIMD)(benchmark::State& state) { - for (auto _ : state) - { - sfz::saturatingSFZIndex(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 2.5f, loopEnd); - } -} - -BENCHMARK_DEFINE_F(SaturatingFixture, Scalar_Unaligned)(benchmark::State& state) { - for (auto _ : state) - { - sfz::saturatingSFZIndex(absl::MakeSpan(jumps).subspan(1), absl::MakeSpan(leftCoeffs).subspan(2), absl::MakeSpan(rightCoeffs).subspan(1), absl::MakeSpan(indices).subspan(3), 2.5f, loopEnd); - } -} - -BENCHMARK_DEFINE_F(SaturatingFixture, SIMD_Unaligned)(benchmark::State& state) { - for (auto _ : state) - { - sfz::saturatingSFZIndex(absl::MakeSpan(jumps).subspan(1), absl::MakeSpan(leftCoeffs).subspan(2), absl::MakeSpan(rightCoeffs).subspan(1), absl::MakeSpan(indices).subspan(3), 2.5f, loopEnd); - } -} - - -// Register the function as a benchmark -BENCHMARK_REGISTER_F(SaturatingFixture, Scalar)->RangeMultiplier(2)->Range((2<<6), (2<<12)); -BENCHMARK_REGISTER_F(SaturatingFixture, SIMD)->RangeMultiplier(2)->Range((2<<6), (2<<12)); -BENCHMARK_REGISTER_F(SaturatingFixture, Scalar_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12)); -BENCHMARK_REGISTER_F(SaturatingFixture, SIMD_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12)); -BENCHMARK_MAIN(); diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index b2fa4195..0fa42459 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -41,8 +41,6 @@ sfizz_add_benchmark(bm_read BM_readInterleaved.cpp) sfizz_add_benchmark(bm_mathfuns BM_mathfuns.cpp) sfizz_add_benchmark(bm_gain BM_gain.cpp) sfizz_add_benchmark(bm_divide BM_divide.cpp) -sfizz_add_benchmark(bm_looping BM_looping.cpp) -sfizz_add_benchmark(bm_saturating BM_saturating.cpp) sfizz_add_benchmark(bm_ramp BM_ramp.cpp) sfizz_add_benchmark(bm_ADSR BM_ADSR.cpp) target_link_libraries(bm_ADSR PRIVATE sfizz::sfizz) diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index 840853a3..4be2cee5 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -152,120 +152,6 @@ void fill(absl::Span output, T value) noexcept absl::c_fill(output, value); } -namespace _internals { - template - inline void snippetSaturatingIndex(const T*& jump, T*& leftCoeff, T*& rightCoeff, int*& index, T& floatIndex, T loopEnd) - { - floatIndex += *jump; - if (floatIndex >= loopEnd) { - floatIndex = loopEnd; - *index = static_cast(floatIndex) - 1; - *rightCoeff = static_cast(1.0); - *leftCoeff = static_cast(0.0); - } else { - *index = static_cast(floatIndex); - *rightCoeff = floatIndex - *index; - *leftCoeff = static_cast(1.0) - *rightCoeff; - } - incrementAll(index, leftCoeff, rightCoeff, jump); - } -} - -/** - * @brief Computes an integer index and 2 float coefficients corresponding to the - * linear interpolation procedure. This version will saturate the index to the upper - * bound if the upper bound is reached. - * - * The indices are computed starting from the given floatIndex, and each increment - * is given by the elements of jumps. - * The output size will be the minimum of the inputs span and outputs span size. - * - * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version - * @param jumps the floating point increments to the index - * @param leftCoeffs the linear interpolation coefficients for the left value - * @param rightCoeffs the linear interpolation coefficients for the right value - * @param indices the integer sample indices for the left values; the right values - * for interpolation at index i are (indices[i] + 1) and not indices[i+1] - * @param floatIndex the starting floating point index - * @param loopEnd the end of the "loop" which is not really a loop because it saturate. - * @return float - */ -template -float saturatingSFZIndex(absl::Span jumps, absl::Span leftCoeffs, absl::Span rightCoeffs, absl::Span indices, T floatIndex, T loopEnd) noexcept -{ - CHECK(indices.size() >= jumps.size()); - CHECK(indices.size() == leftCoeffs.size()); - CHECK(indices.size() == rightCoeffs.size()); - - auto* index = indices.begin(); - auto* leftCoeff = leftCoeffs.begin(); - auto* rightCoeff = rightCoeffs.begin(); - auto* jump = jumps.begin(); - const auto size = min(jumps.size(), indices.size(), leftCoeffs.size(), rightCoeffs.size()); - auto* sentinel = jumps.begin() + size; - - while (jump < sentinel) - _internals::snippetSaturatingIndex(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd); - return floatIndex; -} - -template <> -float saturatingSFZIndex(absl::Span jumps, absl::Span leftCoeffs, absl::Span rightCoeffs, absl::Span indices, float floatIndex, float loopEnd) noexcept; - -namespace _internals { - template - inline void snippetLoopingIndex(const T*& jump, T*& leftCoeff, T*& rightCoeff, int*& index, T& floatIndex, T loopEnd, T loopStart) - { - floatIndex += *jump; - if (floatIndex >= loopEnd) - floatIndex -= loopEnd - loopStart; - *index = static_cast(floatIndex); - *rightCoeff = floatIndex - *index; - *leftCoeff = 1.0f - *rightCoeff; - incrementAll(index, leftCoeff, rightCoeff, jump); - } -} - -/** - * @brief Computes an integer index and 2 float coefficients corresponding to the - * linear interpolation procedure. This version will loop the index at the upper - * bound loopend and restart it at the start of the loop. - * - * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version - * @param jumps the floating point increments to the index - * @param leftCoeffs the linear interpolation coefficients for the left value - * @param rightCoeffs the linear interpolation coefficients for the right value - * @param indices the integer sample indices for the left values; the right values - * for interpolation at index i are (indices[i] + 1) and not indices[i+1] - * @param floatIndex the starting floating point index - * @param loopEnd the end index of the loop - * @param loopStart the start index of the loop - * @return float - */ -template -float loopingSFZIndex(absl::Span jumps, absl::Span leftCoeffs, absl::Span rightCoeffs, absl::Span indices, T floatIndex, T loopEnd, T loopStart) noexcept -{ - CHECK(indices.size() >= jumps.size()); - CHECK(indices.size() == leftCoeffs.size()); - CHECK(indices.size() == rightCoeffs.size()); - - auto* index = indices.begin(); - auto* leftCoeff = leftCoeffs.begin(); - auto* rightCoeff = rightCoeffs.begin(); - auto* jump = jumps.begin(); - const auto size = min(jumps.size(), indices.size(), leftCoeffs.size(), rightCoeffs.size()); - auto* sentinel = jumps.begin() + size; - - while (jump < sentinel) - _internals::snippetLoopingIndex(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd, loopStart); - return floatIndex; -} - -template <> -float loopingSFZIndex(absl::Span jumps, absl::Span leftCoeff, absl::Span rightCoeff, absl::Span indices, float floatIndex, float loopEnd, float loopStart) noexcept; - namespace _internals { template inline void snippetGain(T gain, const T*& input, T*& output) diff --git a/src/sfizz/SIMDSSE.cpp b/src/sfizz/SIMDSSE.cpp index 607ae2e7..0c2f1a8a 100644 --- a/src/sfizz/SIMDSSE.cpp +++ b/src/sfizz/SIMDSSE.cpp @@ -127,120 +127,6 @@ void sfz::multiplyAdd(const float gain, absl::Span inp _internals::snippetMultiplyAdd(gain, in, out); } -template <> -float sfz::loopingSFZIndex(absl::Span jumps, - absl::Span leftCoeffs, - absl::Span rightCoeffs, - absl::Span indices, - float floatIndex, - float loopEnd, - float loopStart) noexcept -{ - CHECK(indices.size() >= jumps.size()); - CHECK(indices.size() == leftCoeffs.size()); - CHECK(indices.size() == rightCoeffs.size()); - - auto index = indices.data(); - auto leftCoeff = leftCoeffs.data(); - auto rightCoeff = rightCoeffs.data(); - auto jump = jumps.data(); - const auto size = min(jumps.size(), indices.size(), leftCoeffs.size(), rightCoeffs.size()); - const auto* sentinel = jumps.begin() + size; - const auto* alignedEnd = prevAligned(sentinel); - - while (unaligned(reinterpret_cast(index), leftCoeff, rightCoeff, jump) && jump < alignedEnd) - _internals::snippetLoopingIndex(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd, loopStart); - - auto mmFloatIndex = _mm_set_ps1(floatIndex); - const auto mmJumpBack = _mm_set1_ps(loopEnd - loopStart); - const auto mmLoopEnd = _mm_set1_ps(loopEnd); - while (jump < alignedEnd) { - auto mmOffset = _mm_load_ps(jump); - mmOffset = _mm_add_ps(mmOffset, _mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(mmOffset), 4))); - mmOffset = _mm_add_ps(mmOffset, _mm_shuffle_ps(_mm_setzero_ps(), mmOffset, 0x40)); - - mmFloatIndex = _mm_add_ps(mmFloatIndex, mmOffset); - const auto mmCompared = _mm_cmpge_ps(mmFloatIndex, mmLoopEnd); - auto mmLoopBack = _mm_sub_ps(mmFloatIndex, mmJumpBack); - mmLoopBack = _mm_and_ps(mmCompared, mmLoopBack); - mmFloatIndex = _mm_andnot_ps(mmCompared, mmFloatIndex); - mmFloatIndex = _mm_add_ps(mmFloatIndex, mmLoopBack); - - auto mmIndices = _mm_cvtps_epi32(_mm_sub_ps(mmFloatIndex, _mm_set_ps1(0.4999999552965164184570312f))); - _mm_store_si128(reinterpret_cast<__m128i*>(index), mmIndices); - - auto mmRight = _mm_sub_ps(mmFloatIndex, _mm_cvtepi32_ps(mmIndices)); - auto mmLeft = _mm_sub_ps(_mm_set_ps1(1.0f), mmRight); - _mm_store_ps(leftCoeff, mmLeft); - _mm_store_ps(rightCoeff, mmRight); - - mmFloatIndex = _mm_shuffle_ps(mmFloatIndex, mmFloatIndex, _MM_SHUFFLE(3, 3, 3, 3)); - // floatingIndex = _mm_cvtss_f32(_mm_shuffle_ps(mmFloatIndex, mmFloatIndex, _MM_SHUFFLE(0, 0, 0, 3)));; - // floatingIndex = *(index + 3) + *(rightCoeff + 3); - incrementAll(index, jump, leftCoeff, rightCoeff); - } - - floatIndex = _mm_cvtss_f32(mmFloatIndex); - while (jump < sentinel) - _internals::snippetLoopingIndex(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd, loopStart); - return floatIndex; -} - -template <> -float sfz::saturatingSFZIndex(absl::Span jumps, - absl::Span leftCoeffs, - absl::Span rightCoeffs, - absl::Span indices, - float floatIndex, - float loopEnd) noexcept -{ - CHECK(indices.size() >= jumps.size()); - CHECK(indices.size() == leftCoeffs.size()); - CHECK(indices.size() == rightCoeffs.size()); - - auto index = indices.data(); - auto leftCoeff = leftCoeffs.data(); - auto rightCoeff = rightCoeffs.data(); - auto jump = jumps.data(); - const auto size = min(jumps.size(), indices.size(), leftCoeffs.size(), rightCoeffs.size()); - const auto* sentinel = jumps.begin() + size; - const auto* alignedEnd = prevAligned(sentinel); - - while (unaligned(reinterpret_cast(index), leftCoeff, rightCoeff, jump) && jump < alignedEnd) - _internals::snippetSaturatingIndex(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd); - - auto mmFloatIndex = _mm_set_ps1(floatIndex); - const auto mmLoopEnd = _mm_set1_ps(loopEnd); - const auto mmSaturated = _mm_sub_ps(mmLoopEnd, _mm_set_ps1(0.000001f)); - while (jump < alignedEnd) { - auto mmOffset = _mm_load_ps(jump); - mmOffset = _mm_add_ps(mmOffset, _mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(mmOffset), 4))); - mmOffset = _mm_add_ps(mmOffset, _mm_shuffle_ps(_mm_setzero_ps(), mmOffset, 0x40)); - - mmFloatIndex = _mm_add_ps(mmFloatIndex, mmOffset); - const auto mmCompared = _mm_cmplt_ps(mmFloatIndex, mmLoopEnd); - mmFloatIndex = _mm_add_ps(_mm_and_ps(mmCompared, mmFloatIndex), _mm_andnot_ps(mmCompared, mmSaturated)); - - auto mmIndices = _mm_cvtps_epi32(_mm_sub_ps(mmFloatIndex, _mm_set_ps1(0.4999999552965164184570312f))); - _mm_store_si128(reinterpret_cast<__m128i*>(index), mmIndices); - - auto mmRight = _mm_sub_ps(mmFloatIndex, _mm_cvtepi32_ps(mmIndices)); - auto mmLeft = _mm_sub_ps(_mm_set_ps1(1.0f), mmRight); - _mm_store_ps(leftCoeff, mmLeft); - _mm_store_ps(rightCoeff, mmRight); - - mmFloatIndex = _mm_shuffle_ps(mmFloatIndex, mmFloatIndex, _MM_SHUFFLE(3, 3, 3, 3)); - // floatingIndex = _mm_cvtss_f32(_mm_shuffle_ps(mmFloatIndex, mmFloatIndex, _MM_SHUFFLE(0, 0, 0, 3)));; - // floatingIndex = *(index + 3) + *(rightCoeff + 3); - incrementAll(index, jump, leftCoeff, rightCoeff); - } - - floatIndex = _mm_cvtss_f32(mmFloatIndex); - while (jump < sentinel) - _internals::snippetSaturatingIndex(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd); - return floatIndex; -} - template <> float sfz::linearRamp(absl::Span output, float value, float step) noexcept { diff --git a/tests/SIMDHelpersT.cpp b/tests/SIMDHelpersT.cpp index 8bf3eed4..20b57866 100644 --- a/tests/SIMDHelpersT.cpp +++ b/tests/SIMDHelpersT.cpp @@ -342,105 +342,6 @@ TEST_CASE("[Helpers] Gain, spans and inplace (SIMD)") REQUIRE(buffer == expected); } -TEST_CASE("[Helpers] SFZ looping index") -{ - std::array jumps { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f }; // 1.1 2.3 3.6 5.0f 6.5 8.1 - std::array indices; - std::array leftCoeffs; - std::array rightCoeffs; - std::array expectedIndices { 2, 3, 4, 1, 2, 4 }; - std::array expectedLeft { 0.9f, 0.7f, 0.4f, 1.0f, 0.5f, 0.9f }; - std::array expectedRight { 0.1f, 0.3f, 0.6f, 0.0f, 0.5f, 0.1f }; - sfz::loopingSFZIndex(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, 6, 1); - REQUIRE(indices == expectedIndices); - REQUIRE(approxEqual(leftCoeffs, expectedLeft)); - REQUIRE(approxEqual(rightCoeffs, expectedRight)); -} - -TEST_CASE("[Helpers] SFZ looping index (SIMD)") -{ - std::array jumps { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f }; // 1.1 2.3 3.6 5.0f 6.5 8.1 - std::array indices; - std::array leftCoeffs; - std::array rightCoeffs; - std::array expectedIndices { 2, 3, 4, 1, 2, 4 }; - std::array expectedLeft { 0.9f, 0.7f, 0.4f, 1.0f, 0.5f, 0.9f }; - std::array expectedRight { 0.1f, 0.3f, 0.6f, 0.0f, 0.5f, 0.1f }; - sfz::loopingSFZIndex(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, 6, 1); - REQUIRE(indices == expectedIndices); - REQUIRE(approxEqual(leftCoeffs, expectedLeft)); - REQUIRE(approxEqual(rightCoeffs, expectedRight)); -} - -// TEST_CASE("[Helpers] SFZ looping index (SIMD vs Scalar)") -// { - -// std::vector jumps(bigBufferSize); -// absl::c_fill(jumps, fillValue); - -// std::vector indices(bigBufferSize); -// std::vector leftCoeffs(bigBufferSize); -// std::vector rightCoeffs(bigBufferSize); - -// std::vector indicesSIMD(bigBufferSize); -// std::vector leftCoeffsSIMD(bigBufferSize); -// std::vector rightCoeffsSIMD(bigBufferSize); -// sfz::loopingSFZIndex(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, medBufferSize, 1); -// sfz::loopingSFZIndex(jumps, absl::MakeSpan(leftCoeffsSIMD), absl::MakeSpan(rightCoeffsSIMD), absl::MakeSpan(indicesSIMD), 1.0f, medBufferSize, 1); -// for (int i = 0; i < bigBufferSize; ++i) -// REQUIRE( ((static_cast(indices[i]) + rightCoeffs[i] == Approx(static_cast(indicesSIMD[i]) + rightCoeffsSIMD[i]).margin(1e-2)) -// || (static_cast(indices[i]) + rightCoeffs[i] == Approx(static_cast(indicesSIMD[i]) + rightCoeffsSIMD[i] - static_cast(medBufferSize)).margin(2e-2))) ); -// } - -TEST_CASE("[Helpers] SFZ saturating index") -{ - std::array jumps { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f }; // 1.1 2.3 3.6 5.0f 6.5 8.1 - std::array indices; - std::array leftCoeffs; - std::array rightCoeffs; - std::array expectedIndices { 2, 3, 4, 5, 5, 5 }; - std::array expectedLeft { 0.9f, 0.7f, 0.4f, 0.0f, 0.0f, 0.0f }; - std::array expectedRight { 0.1f, 0.3f, 0.6f, 1.0f, 1.0f, 1.0f }; - sfz::saturatingSFZIndex(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, 6); - REQUIRE(indices == expectedIndices); - REQUIRE(approxEqual(leftCoeffs, expectedLeft)); - REQUIRE(approxEqual(rightCoeffs, expectedRight)); -} - -TEST_CASE("[Helpers] SFZ saturating index (SIMD)") -{ - std::array jumps { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f }; // 1.1 2.3 3.6 5.0f 6.5 8.1 - std::array indices; - std::array leftCoeffs; - std::array rightCoeffs; - std::array expectedIndices { 2, 3, 4, 5, 5, 5 }; - std::array expectedLeft { 0.9f, 0.7f, 0.4f, 0.0f, 0.0f, 0.0f }; - std::array expectedRight { 0.1f, 0.3f, 0.6f, 1.0f, 1.0f, 1.0f }; - sfz::saturatingSFZIndex(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, 6); - REQUIRE(indices == expectedIndices); - REQUIRE(approxEqualMargin(leftCoeffs, expectedLeft)); - REQUIRE(approxEqualMargin(rightCoeffs, expectedRight)); -} - -TEST_CASE("[Helpers] SFZ saturating index (SIMD vs Scalar)") -{ - - std::vector jumps(medBufferSize); - absl::c_fill(jumps, fillValue); - - std::vector indices(medBufferSize); - std::vector leftCoeffs(medBufferSize); - std::vector rightCoeffs(medBufferSize); - - std::vector indicesSIMD(medBufferSize); - std::vector leftCoeffsSIMD(medBufferSize); - std::vector rightCoeffsSIMD(medBufferSize); - sfz::saturatingSFZIndex(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, 78); - sfz::saturatingSFZIndex(jumps, absl::MakeSpan(leftCoeffsSIMD), absl::MakeSpan(rightCoeffsSIMD), absl::MakeSpan(indicesSIMD), 1.0f, 78); - for (int i = 0; i < medBufferSize; ++i) - REQUIRE( static_cast(indices[i]) + rightCoeffs[i] == Approx(static_cast(indicesSIMD[i]) + rightCoeffsSIMD[i])); -} - TEST_CASE("[Helpers] Linear Ramp") { const float start { 0.0f }; From 1ab1ab802b5f3bdce68d02eec509080f9ae630ed Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 30 May 2020 22:17:33 +0200 Subject: [PATCH 11/42] Moved applyGain to the new mode --- benchmarks/BM_gain.cpp | 12 ++-- src/sfizz/SIMDHelpers.cpp | 59 +++++++++++++++-- src/sfizz/SIMDHelpers.h | 134 ++++++++++++++++++-------------------- src/sfizz/SIMDSSE.cpp | 41 ------------ tests/SIMDHelpersT.cpp | 24 ++++--- 5 files changed, 140 insertions(+), 130 deletions(-) diff --git a/benchmarks/BM_gain.cpp b/benchmarks/BM_gain.cpp index cb355f1f..3a753389 100644 --- a/benchmarks/BM_gain.cpp +++ b/benchmarks/BM_gain.cpp @@ -66,14 +66,14 @@ BENCHMARK_DEFINE_F(GainSingle, Straight)(benchmark::State& state) { BENCHMARK_DEFINE_F(GainSingle, Scalar)(benchmark::State& state) { for (auto _ : state) { - sfz::applyGain(gain, input, absl::MakeSpan(output)); + sfz::applyGain(gain, input, absl::MakeSpan(output)); } } BENCHMARK_DEFINE_F(GainSingle, SIMD)(benchmark::State& state) { for (auto _ : state) { - sfz::applyGain(gain, input, absl::MakeSpan(output)); + sfz::applyGain(gain, input, absl::MakeSpan(output)); } } @@ -88,28 +88,28 @@ BENCHMARK_DEFINE_F(GainArray, Straight)(benchmark::State& state) { BENCHMARK_DEFINE_F(GainArray, Scalar)(benchmark::State& state) { for (auto _ : state) { - sfz::applyGain(gain, input, absl::MakeSpan(output)); + sfz::applyGain(gain, input, absl::MakeSpan(output)); } } BENCHMARK_DEFINE_F(GainArray, SIMD)(benchmark::State& state) { for (auto _ : state) { - sfz::applyGain(gain, input, absl::MakeSpan(output)); + sfz::applyGain(gain, input, absl::MakeSpan(output)); } } BENCHMARK_DEFINE_F(GainArray, Scalar_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::applyGain(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); + sfz::applyGain(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } BENCHMARK_DEFINE_F(GainArray, SIMD_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::applyGain(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); + sfz::applyGain(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index 5308f601..a186280a 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -13,6 +13,7 @@ namespace sfz { static std::array(SIMDOps::_sentinel)> simdStatus; static bool simdStatusInitialized = false; +static cpuid::cpuinfo cpuInfo; void resetSIMDStatus() { @@ -58,7 +59,7 @@ bool getSIMDOpStatus(SIMDOps op) constexpr uintptr_t TypeAlignment = 4; -template +template inline void tickRead(const T*& input, T*& outputLeft, T*& outputRight) { *outputLeft++ = *input++; @@ -75,7 +76,7 @@ inline void tickWrite(T*& output, const T*& inputLeft, const T*& inputRight) void readInterleaved(const float* input, float* outputLeft, float* outputRight, unsigned inputSize) noexcept { const auto sentinel = input + inputSize - 1; - cpuid::cpuinfo cpuInfo; + if (getSIMDOpStatus(SIMDOps::readInterleaved)) { #if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 if (cpuInfo.has_sse()) { @@ -109,8 +110,7 @@ void writeInterleaved(const float* inputLeft, const float* inputRight, float* ou { const auto sentinel = output + outputSize - 1; - cpuid::cpuinfo cpuInfo; - if (getSIMDOpStatus(SIMDOps::readInterleaved)) { + if (getSIMDOpStatus(SIMDOps::writeInterleaved)) { #if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 if (cpuInfo.has_sse()) { const auto* lastAligned = prevAligned(output + outputSize - 4); @@ -136,5 +136,56 @@ void writeInterleaved(const float* inputLeft, const float* inputRight, float* ou tickWrite(output, inputLeft, inputRight); } +template<> +void applyGain(float gain, const float* input, float* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + + if (getSIMDOpStatus(SIMDOps::gain)) { +#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); + while (unaligned(input, output) && output < lastAligned) + *output++ = gain * (*input++); + + while (output < lastAligned) { + _mm_store_ps(output, _mm_mul_ps(mmGain, _mm_load_ps(input))); + incrementAll<4>(input, output); + } + // fallthrough from lastAligned to sentinel + } +#endif + } + + while (output < sentinel) + *output++ = gain * (*input++); } +template<> +void applyGain(const float* gain, const float* input, float* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + + if (getSIMDOpStatus(SIMDOps::gain)) { +#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++ = (*gain++) * (*input++); + + while (output < lastAligned) { + _mm_store_ps(output, _mm_mul_ps(_mm_load_ps(gain), _mm_load_ps(input))); + incrementAll<4>(gain, input, output); + } + // fallthrough from lastAligned to sentinel + } +#endif + } + + while (output < sentinel) + *output++ = (*gain++) * (*input++); +} + +} diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index 4be2cee5..b93f3123 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -112,14 +112,13 @@ void readInterleaved(const float* input, float* outputLeft, float* outputRight, inline void readInterleaved(absl::Span input, absl::Span outputLeft, absl::Span outputRight) noexcept { - // The size of the output is not big enough for the input... - CHECK(outputLeft.size() >= input.size() / 2); - CHECK(outputRight.size() >= input.size() / 2); + // Something is fishy with the sizes + CHECK(outputLeft.size() == input.size() / 2); + CHECK(outputRight.size() == input.size() / 2); const auto size = min(input.size(), 2 * outputLeft.size(), 2 * outputRight.size()); readInterleaved(input.data(), outputLeft.data(), outputRight.data(), size); } - /** * @brief Write a pair of left and right stereo input into a single buffer interleaved. * @@ -132,9 +131,9 @@ void writeInterleaved(const float* inputLeft, const float* inputRight, float* ou inline void writeInterleaved(absl::Span inputLeft, absl::Span inputRight, absl::Span output) noexcept { - // Not enough data in the inputs - CHECK(inputLeft.size() >= output.size() / 2); - CHECK(inputRight.size() >= output.size() / 2); + // Something is fishy with the sizes + CHECK(inputLeft.size() == output.size() / 2); + CHECK(inputRight.size() == output.size() / 2); const auto size = min(output.size(), 2 * inputLeft.size(), 2 * inputRight.size()); writeInterleaved(inputLeft.data(), inputRight.data(), output.data(), size); } @@ -152,103 +151,96 @@ void fill(absl::Span output, T value) noexcept absl::c_fill(output, value); } -namespace _internals { - template - inline void snippetGain(T gain, const T*& input, T*& output) - { - *output++ = gain * (*input++); - } -} - /** * @brief Applies a scalar gain to the input * - * The output size will be the minimum of the input span and output span size. - * - * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version * @param gain the gain to apply * @param input * @param output + * @param size */ -template -void applyGain(T gain, absl::Span input, absl::Span output) noexcept +template +void applyGain(T gain, const T* input, T* output, unsigned size) noexcept { - CHECK(input.size() <= output.size()); - auto* in = input.begin(); - auto* out = output.begin(); - auto* sentinel = out + std::min(output.size(), input.size()); - while (out < sentinel) - _internals::snippetGain(gain, in, out); + const auto sentinel = output + size; + while (output < sentinel) + *output++ = gain * (*input++); } -namespace _internals { - template - inline void snippetGainSpan(const T*& gain, const T*& input, T*& output) - { - *output++ = (*gain++) * (*input++); - } +template<> +void applyGain(float gain, const float* input, float* output, unsigned size) noexcept; + +template +inline void applyGain(T gain, absl::Span input, absl::Span output) noexcept +{ + CHECK_SPAN_SIZES(input, output); + applyGain(gain, input.data(), output.data(), minSpanSize(input, output)); } /** - * @brief Applies a vector gain to an input stap + * @brief Applies a scalar gain inplace * - * The output size will be the minimum of the gain, input span and output span size. + * @param gain the gain to apply + * @param array + * @param size + */ +template +inline void applyGain(float gain, float* array, unsigned size) noexcept +{ + applyGain(gain, array, array, size); +} + +template +inline void applyGain(float gain, absl::Span array) noexcept +{ + applyGain(gain, array.data(), array.data(), array.size()); +} + +/** + * @brief Applies a vector gain to an input span * - * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version * @param gain * @param input * @param output + * @param size */ -template -void applyGain(absl::Span gain, absl::Span input, absl::Span output) noexcept +template +void applyGain(const T* gain, const T* input, T* output, unsigned size) noexcept { - CHECK(gain.size() == input.size()); - CHECK(input.size() <= output.size()); - auto* in = input.begin(); - auto* g = gain.begin(); - auto* out = output.begin(); - auto* sentinel = out + std::min(gain.size(), std::min(output.size(), input.size())); - while (out < sentinel) - _internals::snippetGainSpan(g, in, out); + const auto sentinel = output + size; + while (output < sentinel) + *output++ = (*gain++) * (*input++); } -/** - * @brief Applies a scalar gain in-place on a span - * - * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version - * @param gain - * @param output - */ -template -void applyGain(T gain, absl::Span output) noexcept +template<> +void applyGain(const float* gain, const float* input, float* output, unsigned size) noexcept; + +template +inline void applyGain(absl::Span gain, absl::Span input, absl::Span output) noexcept { - applyGain(gain, output, output); + CHECK_SPAN_SIZES(gain, input, output); + applyGain(gain.data(), input.data(), output.data(), minSpanSize(gain, input, output)); } /** * @brief Applies a vector gain in-place on a span * - * The output size will be the minimum of the gain span and output span size. - * - * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version * @param gain - * @param output + * @param array + * @param size */ -template -void applyGain(absl::Span gain, absl::Span output) noexcept +template +inline void applyGain(const T* gain, T* array, unsigned size) noexcept { - applyGain(gain, output, output); + applyGain(gain, array, array, size); } -template <> -void applyGain(float gain, absl::Span input, absl::Span output) noexcept; - -template <> -void applyGain(absl::Span gain, absl::Span input, absl::Span output) noexcept; +template +inline void applyGain(absl::Span gain, absl::Span array) noexcept +{ + CHECK_SPAN_SIZES(gain, array); + applyGain(gain.data(), array.data(), array.data(), minSpanSize(gain, array)); +} namespace _internals { template diff --git a/src/sfizz/SIMDSSE.cpp b/src/sfizz/SIMDSSE.cpp index 0c2f1a8a..5b893b80 100644 --- a/src/sfizz/SIMDSSE.cpp +++ b/src/sfizz/SIMDSSE.cpp @@ -16,47 +16,6 @@ constexpr uintptr_t TypeAlignment = 4; -template <> -void sfz::applyGain(float gain, absl::Span input, absl::Span output) noexcept -{ - auto* in = input.begin(); - auto* out = output.begin(); - const auto size = std::min(output.size(), input.size()); - const auto* lastAligned = prevAligned(output.begin() + size); - const auto mmGain = _mm_set_ps1(gain); - - while (unaligned(out, in) && out < lastAligned) - *out++ = gain * (*in++); - - while (out < lastAligned) { - _mm_store_ps(out, _mm_mul_ps(mmGain, _mm_load_ps(in))); - incrementAll(out, in); - } - - while (out < output.end()) - *out++ = gain * (*in++); -} - -template <> -void sfz::applyGain(absl::Span gain, absl::Span input, absl::Span output) noexcept -{ - auto* in = input.begin(); - auto* out = output.begin(); - auto* g = gain.begin(); - const auto size = std::min(output.size(), std::min(input.size(), gain.size())); - const auto* lastAligned = prevAligned(output.begin() + size); - - while (unaligned(out, in, g) && out < lastAligned) - _internals::snippetGainSpan(g, in, out); - - while (out < lastAligned) { - _mm_store_ps(out, _mm_mul_ps(_mm_load_ps(g), _mm_load_ps(in))); - incrementAll(g, in, out); - } - - while (out < output.end()) - _internals::snippetGainSpan(g, in, out); -} template <> diff --git a/tests/SIMDHelpersT.cpp b/tests/SIMDHelpersT.cpp index 20b57866..5b547dcf 100644 --- a/tests/SIMDHelpersT.cpp +++ b/tests/SIMDHelpersT.cpp @@ -275,7 +275,8 @@ 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::applyGain(fillValue, input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); + sfz::applyGain(fillValue, input, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -283,7 +284,8 @@ 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::applyGain(fillValue, buffer, absl::MakeSpan(buffer)); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); + sfz::applyGain(fillValue, buffer, absl::MakeSpan(buffer)); REQUIRE(buffer == expected); } @@ -293,7 +295,8 @@ TEST_CASE("[Helpers] Gain, spans") 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::applyGain(gain, input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); + sfz::applyGain(gain, input, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -302,7 +305,8 @@ 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::applyGain(gain, buffer, absl::MakeSpan(buffer)); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); + sfz::applyGain(gain, buffer, absl::MakeSpan(buffer)); REQUIRE(buffer == expected); } @@ -311,7 +315,8 @@ 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::applyGain(fillValue, input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); + sfz::applyGain(fillValue, input, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -319,7 +324,8 @@ 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::applyGain(fillValue, buffer, absl::MakeSpan(buffer)); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); + sfz::applyGain(fillValue, buffer, absl::MakeSpan(buffer)); REQUIRE(buffer == expected); } @@ -329,7 +335,8 @@ TEST_CASE("[Helpers] Gain, spans (SIMD)") 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::applyGain(gain, input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); + sfz::applyGain(gain, input, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -338,7 +345,8 @@ 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::applyGain(gain, buffer, absl::MakeSpan(buffer)); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); + sfz::applyGain(gain, buffer, absl::MakeSpan(buffer)); REQUIRE(buffer == expected); } From 1b68331f385e4df3ffa91cab0ae87b5588ed6aea Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 30 May 2020 22:26:35 +0200 Subject: [PATCH 12/42] Moved divide to the new format --- benchmarks/BM_divide.cpp | 8 +++---- src/sfizz/SIMDHelpers.cpp | 26 ++++++++++++++++++++++ src/sfizz/SIMDHelpers.h | 45 +++++++++++++++++---------------------- src/sfizz/SIMDSSE.cpp | 24 --------------------- 4 files changed, 49 insertions(+), 54 deletions(-) diff --git a/benchmarks/BM_divide.cpp b/benchmarks/BM_divide.cpp index b4fed561..770fac78 100644 --- a/benchmarks/BM_divide.cpp +++ b/benchmarks/BM_divide.cpp @@ -46,28 +46,28 @@ BENCHMARK_DEFINE_F(Divide, Straight)(benchmark::State& state) { BENCHMARK_DEFINE_F(Divide, Scalar)(benchmark::State& state) { for (auto _ : state) { - sfz::divide(input, divisor, absl::MakeSpan(output)); + sfz::divide(input, divisor, absl::MakeSpan(output)); } } BENCHMARK_DEFINE_F(Divide, SIMD)(benchmark::State& state) { for (auto _ : state) { - sfz::divide(input, divisor, absl::MakeSpan(output)); + sfz::divide(input, divisor, absl::MakeSpan(output)); } } BENCHMARK_DEFINE_F(Divide, Scalar_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::divide(absl::MakeSpan(input).subspan(1), absl::MakeSpan(divisor).subspan(1), absl::MakeSpan(output).subspan(1)); + sfz::divide(absl::MakeSpan(input).subspan(1), absl::MakeSpan(divisor).subspan(1), absl::MakeSpan(output).subspan(1)); } } BENCHMARK_DEFINE_F(Divide, SIMD_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::divide(absl::MakeSpan(input).subspan(1), absl::MakeSpan(divisor).subspan(1), absl::MakeSpan(output).subspan(1)); + sfz::divide(absl::MakeSpan(input).subspan(1), absl::MakeSpan(divisor).subspan(1), absl::MakeSpan(output).subspan(1)); } } diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index a186280a..3aba1f84 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -188,4 +188,30 @@ void applyGain(const float* gain, const float* input, float* output, unsi *output++ = (*gain++) * (*input++); } +template <> +void sfz::divide(const float* input, const float* divisor, float* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + + if (getSIMDOpStatus(SIMDOps::divide)) { +#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++) / (*divisor++); + + while (output < lastAligned) { + _mm_store_ps(output, _mm_div_ps(_mm_load_ps(input), _mm_load_ps(divisor))); + incrementAll<4>(divisor, input, output); + } + // fallthrough from lastAligned to sentinel + } +#endif + } + + while (output < sentinel) + *output++ = (*input++) / (*divisor++); +} + } diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index b93f3123..8a722109 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -242,56 +242,49 @@ inline void applyGain(absl::Span gain, absl::Span array) noexcept applyGain(gain.data(), array.data(), array.data(), minSpanSize(gain, array)); } -namespace _internals { - template - inline void snippetDivSpan(const T*& input, const T*& divisor,T*& output) - { - *output++ = (*input++) / (*divisor++); - } -} - /** * @brief Divide a vector by another vector * * The output size will be the minimum of the divisor, input span and output span size. * * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version * @param input * @param divisor * @param output + * @param size */ -template -void divide(absl::Span input, absl::Span divisor, absl::Span output) noexcept +template +void divide(const T* input, const T* divisor, T* output, unsigned size) noexcept { - CHECK(divisor.size() == input.size()); - CHECK(input.size() <= output.size()); - auto* in = input.begin(); - auto* d = divisor.begin(); - auto* out = output.begin(); - auto* sentinel = out + std::min(divisor.size(), std::min(output.size(), input.size())); - while (out < sentinel) - _internals::snippetDivSpan(in, d, out); + const auto sentinel = output + size; + while (output < sentinel) + *output++ = (*input++) / (*divisor++); +} + +template <> +void divide(const float* input, const float* divisor, float* output, unsigned size) noexcept; + +template +inline void divide(absl::Span input, absl::Span divisor, absl::Span output) noexcept +{ + CHECK_SPAN_SIZES(input, divisor, output); + divide(input.data(), divisor.data(), output.data(), minSpanSize(input, divisor, output)); } /** * @brief Divide a vector by another in place * * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version * @param output * @param divisor */ -template +template void divide(absl::Span output, absl::Span divisor) noexcept { - divide(output, divisor, output); + CHECK_SPAN_SIZES(divisor, output); + divide(output.data(), divisor.data(), output.data(), minSpanSize(divisor, output)); } -template <> -void divide(absl::Span input, absl::Span divisor, absl::Span output) noexcept; - - namespace _internals { template inline void snippetMultiplyAdd(const T*& gain, const T*& input, T*& output) diff --git a/src/sfizz/SIMDSSE.cpp b/src/sfizz/SIMDSSE.cpp index 5b893b80..0f4a807c 100644 --- a/src/sfizz/SIMDSSE.cpp +++ b/src/sfizz/SIMDSSE.cpp @@ -16,30 +16,6 @@ constexpr uintptr_t TypeAlignment = 4; - - -template <> -void sfz::divide(absl::Span input, absl::Span divisor, absl::Span output) noexcept -{ - auto* in = input.begin(); - auto* out = output.begin(); - auto* div = divisor.begin(); - const auto size = std::min(output.size(), std::min(input.size(), divisor.size())); - const auto* lastAligned = prevAligned(output.begin() + size); - - while (unaligned(out, in, div) && out < lastAligned) - _internals::snippetDivSpan(in, div, out); - - while (out < lastAligned) { - _mm_store_ps(out, _mm_div_ps(_mm_load_ps(in), _mm_load_ps(div))); - incrementAll(in, div, out); - } - - while (out < output.end()) - _internals::snippetDivSpan(in, div, out); -} - - template <> void sfz::multiplyAdd(absl::Span gain, absl::Span input, absl::Span output) noexcept { From 7b6914f91dcf8f2ec0b28f4e70385053c4083389 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 30 May 2020 22:53:41 +0200 Subject: [PATCH 13/42] Corrected the benchmarks to properly set the SIMD operations --- benchmarks/BM_divide.cpp | 4 ++++ benchmarks/BM_gain.cpp | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/benchmarks/BM_divide.cpp b/benchmarks/BM_divide.cpp index 770fac78..48f5064e 100644 --- a/benchmarks/BM_divide.cpp +++ b/benchmarks/BM_divide.cpp @@ -46,6 +46,7 @@ BENCHMARK_DEFINE_F(Divide, Straight)(benchmark::State& state) { BENCHMARK_DEFINE_F(Divide, Scalar)(benchmark::State& state) { for (auto _ : state) { + sfz::setSIMDOpStatus(sfz::SIMDOps::divide, false); sfz::divide(input, divisor, absl::MakeSpan(output)); } } @@ -53,6 +54,7 @@ BENCHMARK_DEFINE_F(Divide, Scalar)(benchmark::State& state) { BENCHMARK_DEFINE_F(Divide, SIMD)(benchmark::State& state) { for (auto _ : state) { + sfz::setSIMDOpStatus(sfz::SIMDOps::divide, true); sfz::divide(input, divisor, absl::MakeSpan(output)); } } @@ -60,6 +62,7 @@ BENCHMARK_DEFINE_F(Divide, SIMD)(benchmark::State& state) { BENCHMARK_DEFINE_F(Divide, Scalar_Unaligned)(benchmark::State& state) { for (auto _ : state) { + sfz::setSIMDOpStatus(sfz::SIMDOps::divide, false); sfz::divide(absl::MakeSpan(input).subspan(1), absl::MakeSpan(divisor).subspan(1), absl::MakeSpan(output).subspan(1)); } } @@ -67,6 +70,7 @@ BENCHMARK_DEFINE_F(Divide, Scalar_Unaligned)(benchmark::State& state) { BENCHMARK_DEFINE_F(Divide, SIMD_Unaligned)(benchmark::State& state) { for (auto _ : state) { + sfz::setSIMDOpStatus(sfz::SIMDOps::divide, true); sfz::divide(absl::MakeSpan(input).subspan(1), absl::MakeSpan(divisor).subspan(1), absl::MakeSpan(output).subspan(1)); } } diff --git a/benchmarks/BM_gain.cpp b/benchmarks/BM_gain.cpp index 3a753389..cd2096d7 100644 --- a/benchmarks/BM_gain.cpp +++ b/benchmarks/BM_gain.cpp @@ -66,6 +66,7 @@ BENCHMARK_DEFINE_F(GainSingle, Straight)(benchmark::State& state) { BENCHMARK_DEFINE_F(GainSingle, Scalar)(benchmark::State& state) { for (auto _ : state) { + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); sfz::applyGain(gain, input, absl::MakeSpan(output)); } } @@ -73,6 +74,7 @@ BENCHMARK_DEFINE_F(GainSingle, Scalar)(benchmark::State& state) { BENCHMARK_DEFINE_F(GainSingle, SIMD)(benchmark::State& state) { for (auto _ : state) { + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); sfz::applyGain(gain, input, absl::MakeSpan(output)); } } @@ -88,6 +90,7 @@ BENCHMARK_DEFINE_F(GainArray, Straight)(benchmark::State& state) { BENCHMARK_DEFINE_F(GainArray, Scalar)(benchmark::State& state) { for (auto _ : state) { + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); sfz::applyGain(gain, input, absl::MakeSpan(output)); } } @@ -95,6 +98,7 @@ BENCHMARK_DEFINE_F(GainArray, Scalar)(benchmark::State& state) { BENCHMARK_DEFINE_F(GainArray, SIMD)(benchmark::State& state) { for (auto _ : state) { + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); sfz::applyGain(gain, input, absl::MakeSpan(output)); } } @@ -102,6 +106,7 @@ BENCHMARK_DEFINE_F(GainArray, SIMD)(benchmark::State& state) { BENCHMARK_DEFINE_F(GainArray, Scalar_Unaligned)(benchmark::State& state) { for (auto _ : state) { + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); sfz::applyGain(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } @@ -109,6 +114,7 @@ BENCHMARK_DEFINE_F(GainArray, Scalar_Unaligned)(benchmark::State& state) { BENCHMARK_DEFINE_F(GainArray, SIMD_Unaligned)(benchmark::State& state) { for (auto _ : state) { + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); sfz::applyGain(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } From 3e6d9e350422aa3bbd2b2e4370abc79748f6e7f8 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 30 May 2020 22:53:53 +0200 Subject: [PATCH 14/42] Moved multiplyAdd to the new format --- benchmarks/BM_multiplyAdd.cpp | 12 +++-- benchmarks/BM_multiplyAddFixedGain.cpp | 12 +++-- src/sfizz/SIMDHelpers.cpp | 65 ++++++++++++++++++++++-- src/sfizz/SIMDHelpers.h | 69 +++++++++++++------------- src/sfizz/SIMDSSE.cpp | 46 ----------------- tests/SIMDHelpersT.cpp | 40 ++++++++++++--- 6 files changed, 144 insertions(+), 100 deletions(-) diff --git a/benchmarks/BM_multiplyAdd.cpp b/benchmarks/BM_multiplyAdd.cpp index 4bb01e3b..a85e28ab 100644 --- a/benchmarks/BM_multiplyAdd.cpp +++ b/benchmarks/BM_multiplyAdd.cpp @@ -46,28 +46,32 @@ BENCHMARK_DEFINE_F(MultiplyAdd, Straight)(benchmark::State& state) { BENCHMARK_DEFINE_F(MultiplyAdd, Scalar)(benchmark::State& state) { for (auto _ : state) { - sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); + sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); } } BENCHMARK_DEFINE_F(MultiplyAdd, SIMD)(benchmark::State& state) { for (auto _ : state) { - sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); + sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); } } BENCHMARK_DEFINE_F(MultiplyAdd, Scalar_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::multiplyAdd(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); + sfz::multiplyAdd(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } BENCHMARK_DEFINE_F(MultiplyAdd, SIMD_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::multiplyAdd(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); + sfz::multiplyAdd(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } diff --git a/benchmarks/BM_multiplyAddFixedGain.cpp b/benchmarks/BM_multiplyAddFixedGain.cpp index e05635ba..97a4001a 100644 --- a/benchmarks/BM_multiplyAddFixedGain.cpp +++ b/benchmarks/BM_multiplyAddFixedGain.cpp @@ -48,7 +48,8 @@ BENCHMARK_DEFINE_F(MultiplyAddFixedGain, Scalar) (benchmark::State& state) { for (auto _ : state) { - sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); + sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); } } @@ -56,7 +57,8 @@ BENCHMARK_DEFINE_F(MultiplyAddFixedGain, SIMD) (benchmark::State& state) { for (auto _ : state) { - sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); + sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); } } @@ -64,7 +66,8 @@ BENCHMARK_DEFINE_F(MultiplyAddFixedGain, Scalar_Unaligned) (benchmark::State& state) { for (auto _ : state) { - sfz::multiplyAdd(gain, absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); + sfz::multiplyAdd(gain, absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } @@ -72,7 +75,8 @@ BENCHMARK_DEFINE_F(MultiplyAddFixedGain, SIMD_Unaligned) (benchmark::State& state) { for (auto _ : state) { - sfz::multiplyAdd(gain, absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); + sfz::multiplyAdd(gain, absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index 3aba1f84..5be73cac 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -17,10 +17,10 @@ static cpuid::cpuinfo cpuInfo; void resetSIMDStatus() { - simdStatus[static_cast(SIMDOps::writeInterleaved)] = true; - simdStatus[static_cast(SIMDOps::readInterleaved)] = true; + simdStatus[static_cast(SIMDOps::writeInterleaved)] = false; + simdStatus[static_cast(SIMDOps::readInterleaved)] = false; simdStatus[static_cast(SIMDOps::fill)] = true; - simdStatus[static_cast(SIMDOps::gain)] = false; + simdStatus[static_cast(SIMDOps::gain)] = true; simdStatus[static_cast(SIMDOps::divide)] = false; simdStatus[static_cast(SIMDOps::mathfuns)] = false; simdStatus[static_cast(SIMDOps::loopingSFZIndex)] = true; @@ -136,7 +136,7 @@ void writeInterleaved(const float* inputLeft, const float* inputRight, float* ou tickWrite(output, inputLeft, inputRight); } -template<> +template <> void applyGain(float gain, const float* input, float* output, unsigned size) noexcept { const auto sentinel = output + size; @@ -162,7 +162,7 @@ void applyGain(float gain, const float* input, float* output, unsigned si *output++ = gain * (*input++); } -template<> +template <> void applyGain(const float* gain, const float* input, float* output, unsigned size) noexcept { const auto sentinel = output + size; @@ -214,4 +214,59 @@ void sfz::divide(const float* input, const float* divisor, float* output, *output++ = (*input++) / (*divisor++); } +template <> +void sfz::multiplyAdd(const float* gain, const float* input, float* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + + if (getSIMDOpStatus(SIMDOps::multiplyAdd)) { +#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++ += (*gain++) * (*input++); + + while (output < lastAligned) { + auto mmOut = _mm_load_ps(output); + mmOut = _mm_add_ps(_mm_mul_ps(_mm_load_ps(gain), _mm_load_ps(input)), mmOut); + _mm_store_ps(output, mmOut); + incrementAll<4>(gain, input, output); + } + // fallthrough from lastAligned to sentinel + } +#endif + } + + while (output < sentinel) + *output++ += (*gain++) * (*input++); +} + +template <> +void sfz::multiplyAdd(float gain, const float* input, float* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + + if (getSIMDOpStatus(SIMDOps::multiplyAdd)) { +#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++ += gain * (*input++); + + auto mmGain = _mm_set1_ps(gain); + while (output < lastAligned) { + auto mmOut = _mm_load_ps(output); + mmOut = _mm_add_ps(_mm_mul_ps(mmGain, _mm_load_ps(input)), mmOut); + _mm_store_ps(output, mmOut); + incrementAll<4>(input, output); + } + // fallthrough from lastAligned to sentinel + } +#endif + } + + while (output < sentinel) + *output++ += gain * (*input++); +} + } diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index 8a722109..b190293f 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -285,61 +285,60 @@ void divide(absl::Span output, absl::Span divisor) noexcept divide(output.data(), divisor.data(), output.data(), minSpanSize(divisor, output)); } -namespace _internals { - template - inline void snippetMultiplyAdd(const T*& gain, const T*& input, T*& output) - { +/** + * @brief Applies a gain to the input and add it on the output + * + * @tparam T the underlying type + * @param gain + * @param input + * @param output + * @param size + */ +template +void multiplyAdd(const T* gain, const T* input, T* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + while (output < sentinel) *output++ += (*gain++) * (*input++); - } +} - template - inline void snippetMultiplyAdd(const T gain, const T*& input, T*& output) - { - *output++ += gain * (*input++); - } +template <> +void multiplyAdd(const float* gain, const float* input, float* output, unsigned size) noexcept; + +template +void multiplyAdd(absl::Span gain, absl::Span input, absl::Span output) noexcept +{ + CHECK_SPAN_SIZES(gain, input, output); + multiplyAdd(gain.data(), input.data(), output.data(), minSpanSize(gain, input, output)); } /** * @brief Applies a gain to the input and add it on the output * - * 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 gain * @param input * @param output + * @param size */ -template -void multiplyAdd(absl::Span gain, absl::Span input, absl::Span output) noexcept +template +void multiplyAdd(T gain, const T* input, T* output, unsigned size) noexcept { - CHECK(gain.size() == input.size()); - CHECK(input.size() <= output.size()); - auto* in = input.begin(); - auto* g = gain.begin(); - auto* out = output.begin(); - auto* sentinel = out + std::min(gain.size(), std::min(output.size(), input.size())); - while (out < sentinel) - _internals::snippetMultiplyAdd(g, in, out); + const auto sentinel = output + size; + while (output < sentinel) + *output++ += gain * (*input++); } template <> -void multiplyAdd(absl::Span gain, absl::Span input, absl::Span output) noexcept; +void multiplyAdd(float gain, const float* input, float* output, unsigned size) noexcept; -template -void multiplyAdd(const T gain, absl::Span input, absl::Span output) noexcept +template +void multiplyAdd(T gain, absl::Span input, absl::Span output) noexcept { - // CHECK(input.size() <= output.size()); - auto* in = input.begin(); - auto* out = output.begin(); - auto* sentinel = out + std::min(output.size(), input.size()); - while (out < sentinel) - _internals::snippetMultiplyAdd(gain, in, out); + CHECK_SPAN_SIZES(input, output); + multiplyAdd(gain, input.data(), output.data(), minSpanSize(input, output)); } -template <> -void multiplyAdd(const float gain, absl::Span input, absl::Span output) noexcept; - namespace _internals { template inline void snippetRampLinear(T*& output, T& value, T step) diff --git a/src/sfizz/SIMDSSE.cpp b/src/sfizz/SIMDSSE.cpp index 0f4a807c..d9be6492 100644 --- a/src/sfizz/SIMDSSE.cpp +++ b/src/sfizz/SIMDSSE.cpp @@ -16,52 +16,6 @@ constexpr uintptr_t TypeAlignment = 4; -template <> -void sfz::multiplyAdd(absl::Span gain, absl::Span input, absl::Span output) noexcept -{ - auto* in = input.begin(); - auto* out = output.begin(); - auto* g = gain.begin(); - const auto size = std::min(output.size(), std::min(input.size(), gain.size())); - const auto* lastAligned = prevAligned(output.begin() + size); - - while (unaligned(out, in, g) && out < lastAligned) - _internals::snippetMultiplyAdd(g, in, out); - - while (out < lastAligned) { - auto mmOut = _mm_load_ps(out); - mmOut = _mm_add_ps(_mm_mul_ps(_mm_load_ps(g), _mm_load_ps(in)), mmOut); - _mm_store_ps(out, mmOut); - incrementAll(g, in, out); - } - - while (out < output.end()) - _internals::snippetMultiplyAdd(g, in, out); -} - -template <> -void sfz::multiplyAdd(const float gain, absl::Span input, absl::Span output) noexcept -{ - auto* in = input.begin(); - auto* out = output.begin(); - const auto size = std::min(output.size(), input.size()); - const auto* lastAligned = prevAligned(output.begin() + size); - - while (unaligned(out, in) && out < lastAligned) - _internals::snippetMultiplyAdd(gain, in, out); - - auto mmGain = _mm_set1_ps(gain); - while (out < lastAligned) { - auto mmOut = _mm_load_ps(out); - mmOut = _mm_add_ps(_mm_mul_ps(mmGain, _mm_load_ps(in)), mmOut); - _mm_store_ps(out, mmOut); - incrementAll(in, out); - } - - while (out < output.end()) - _internals::snippetMultiplyAdd(gain, in, out); -} - template <> float sfz::linearRamp(absl::Span output, float value, float step) noexcept { diff --git a/tests/SIMDHelpersT.cpp b/tests/SIMDHelpersT.cpp index 5b547dcf..bd864e52 100644 --- a/tests/SIMDHelpersT.cpp +++ b/tests/SIMDHelpersT.cpp @@ -462,13 +462,25 @@ TEST_CASE("[Helpers] Add (SIMD vs scalar)") REQUIRE(approxEqual(outputScalar, outputSIMD)); } +TEST_CASE("[Helpers] MultiplyAdd (Scalar)") +{ + std::array gain { 0.0f, 0.1f, 0.2f, 0.3f, 0.4f }; + std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; + std::array output { 5.0f, 4.0f, 3.0f, 2.0f, 1.0f }; + std::array expected { 5.0f, 4.2f, 3.6f, 3.2f, 3.0f }; + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); + sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); + REQUIRE(output == expected); +} + TEST_CASE("[Helpers] MultiplyAdd (SIMD)") { std::array gain { 0.0f, 0.1f, 0.2f, 0.3f, 0.4f }; std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 5.0f, 4.0f, 3.0f, 2.0f, 1.0f }; std::array expected { 5.0f, 4.2f, 3.6f, 3.2f, 3.0f }; - sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); + sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -483,18 +495,32 @@ TEST_CASE("[Helpers] MultiplyAdd (SIMD vs scalar)") absl::c_iota(outputScalar, 0.0f); absl::c_iota(outputSIMD, 0.0f); - sfz::multiplyAdd(gain, input, absl::MakeSpan(outputScalar)); - sfz::multiplyAdd(gain, input, absl::MakeSpan(outputSIMD)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); + sfz::multiplyAdd(gain, input, absl::MakeSpan(outputScalar)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); + sfz::multiplyAdd(gain, input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } +TEST_CASE("[Helpers] MultiplyAdd fixed gain (Scalar)") +{ + float gain = 0.3f; + std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; + std::array output { 5.0f, 4.0f, 3.0f, 2.0f, 1.0f }; + std::array expected { 5.3f, 4.6f, 3.9f, 3.2f, 2.5f }; + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); + sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); + REQUIRE(output == expected); +} + TEST_CASE("[Helpers] MultiplyAdd fixed gain (SIMD)") { float gain = 0.3f; std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 5.0f, 4.0f, 3.0f, 2.0f, 1.0f }; std::array expected { 5.3f, 4.6f, 3.9f, 3.2f, 2.5f }; - sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); + sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -508,8 +534,10 @@ TEST_CASE("[Helpers] MultiplyAdd fixed gain (SIMD vs scalar)") absl::c_iota(outputScalar, 0.0f); absl::c_iota(outputSIMD, 0.0f); - sfz::multiplyAdd(gain, input, absl::MakeSpan(outputScalar)); - sfz::multiplyAdd(gain, input, absl::MakeSpan(outputSIMD)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); + sfz::multiplyAdd(gain, input, absl::MakeSpan(outputScalar)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); + sfz::multiplyAdd(gain, input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } From 2ae74bad761e84ae86d8e844421f0bcb0c987ebb Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 30 May 2020 23:06:02 +0200 Subject: [PATCH 15/42] Removed explicit qualifier --- src/sfizz/SIMDHelpers.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index 5be73cac..14c6275b 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -189,7 +189,7 @@ void applyGain(const float* gain, const float* input, float* output, unsi } template <> -void sfz::divide(const float* input, const float* divisor, float* output, unsigned size) noexcept +void divide(const float* input, const float* divisor, float* output, unsigned size) noexcept { const auto sentinel = output + size; @@ -215,7 +215,7 @@ void sfz::divide(const float* input, const float* divisor, float* output, } template <> -void sfz::multiplyAdd(const float* gain, const float* input, float* output, unsigned size) noexcept +void multiplyAdd(const float* gain, const float* input, float* output, unsigned size) noexcept { const auto sentinel = output + size; @@ -242,7 +242,7 @@ void sfz::multiplyAdd(const float* gain, const float* input, float* outpu } template <> -void sfz::multiplyAdd(float gain, const float* input, float* output, unsigned size) noexcept +void multiplyAdd(float gain, const float* input, float* output, unsigned size) noexcept { const auto sentinel = output + size; From 8c6a01a06636ef464b67546a5a8ee91a418d24ce Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 30 May 2020 23:25:12 +0200 Subject: [PATCH 16/42] Moved the ramps to the new format --- benchmarks/BM_ramp.cpp | 24 +++++++++----- src/sfizz/SIMDHelpers.cpp | 70 +++++++++++++++++++++++++++++++++++++++ src/sfizz/SIMDHelpers.h | 55 ++++++++++++++++-------------- src/sfizz/SIMDSSE.cpp | 49 --------------------------- tests/SIMDHelpersT.cpp | 38 ++++++++++++++------- 5 files changed, 143 insertions(+), 93 deletions(-) diff --git a/benchmarks/BM_ramp.cpp b/benchmarks/BM_ramp.cpp index 2a056392..ef2b5379 100644 --- a/benchmarks/BM_ramp.cpp +++ b/benchmarks/BM_ramp.cpp @@ -30,7 +30,8 @@ static void LinearScalar(benchmark::State& state) { for (auto _ : state) { auto value = dist(gen); - sfz::linearRamp(absl::MakeSpan(output), 0.0f, value); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, false); + sfz::linearRamp(absl::MakeSpan(output), 0.0f, value); } } @@ -42,7 +43,8 @@ static void LinearSIMD(benchmark::State& state) { for (auto _ : state) { auto value = dist(gen); - sfz::linearRamp(absl::MakeSpan(output), 0.0f, value); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); + sfz::linearRamp(absl::MakeSpan(output), 0.0f, value); } } static void LinearScalarUnaligned(benchmark::State& state) { @@ -53,7 +55,8 @@ static void LinearScalarUnaligned(benchmark::State& state) { for (auto _ : state) { auto value = dist(gen); - sfz::linearRamp(absl::MakeSpan(output).subspan(1), 0.0f, value); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, false); + sfz::linearRamp(absl::MakeSpan(output).subspan(1), 0.0f, value); } } @@ -65,7 +68,8 @@ static void LinearSIMDUnaligned(benchmark::State& state) { for (auto _ : state) { auto value = dist(gen); - sfz::linearRamp(absl::MakeSpan(output).subspan(1), 0.0f, value); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); + sfz::linearRamp(absl::MakeSpan(output).subspan(1), 0.0f, value); } } @@ -77,7 +81,8 @@ static void MulScalar(benchmark::State& state) { for (auto _ : state) { auto value = dist(gen); - sfz::multiplicativeRamp(absl::MakeSpan(output), 1.0f, value); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, false); + sfz::multiplicativeRamp(absl::MakeSpan(output), 1.0f, value); } } @@ -89,7 +94,8 @@ static void MulSIMD(benchmark::State& state) { for (auto _ : state) { auto value = dist(gen); - sfz::multiplicativeRamp(absl::MakeSpan(output), 1.0f, value); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, true); + sfz::multiplicativeRamp(absl::MakeSpan(output), 1.0f, value); } } static void MulScalarUnaligned(benchmark::State& state) { @@ -100,7 +106,8 @@ static void MulScalarUnaligned(benchmark::State& state) { for (auto _ : state) { auto value = dist(gen); - sfz::multiplicativeRamp(absl::MakeSpan(output).subspan(1), 1.0f, value); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, false); + sfz::multiplicativeRamp(absl::MakeSpan(output).subspan(1), 1.0f, value); } } @@ -112,7 +119,8 @@ static void MulSIMDUnaligned(benchmark::State& state) { for (auto _ : state) { auto value = dist(gen); - sfz::multiplicativeRamp(absl::MakeSpan(output).subspan(1), 1.0f, value); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, true); + sfz::multiplicativeRamp(absl::MakeSpan(output).subspan(1), 1.0f, value); } } diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index 14c6275b..bcb56197 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -269,4 +269,74 @@ void multiplyAdd(float gain, const float* input, float* output, unsigned *output++ += gain * (*input++); } +template <> +float linearRamp(float* output, float start, float step, unsigned size) noexcept +{ + const auto sentinel = output + size; + + if (getSIMDOpStatus(SIMDOps::linearRamp)) { +#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++ = start; + start += step; + } + + auto mmStart = _mm_set1_ps(start - step); + auto mmStep = _mm_set_ps(step + step + step + step, step + step + step, step + step, step); + while (output < lastAligned) { + 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); + } + start = _mm_cvtss_f32(mmStart) + step; + // fallthrough from lastAligned to sentinel + } +#endif + } + + while (output < sentinel) { + *output++ = start; + start += step; + } + return start; +} + +template <> +float multiplicativeRamp(float* output, float start, float step, unsigned size) noexcept +{ + const auto sentinel = output + size; + + if (getSIMDOpStatus(SIMDOps::linearRamp)) { +#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++ = start; + start *= step; + } + + auto mmStart = _mm_set1_ps(start / step); + auto mmStep = _mm_set_ps(step * step * step * step, step * step * step, step * step, step); + while (output < lastAligned) { + 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); + } + start = _mm_cvtss_f32(mmStart) * step; + // fallthrough from lastAligned to sentinel + } +#endif + } + + while (output < sentinel) { + *output++ = start; + start *= step; + } + return start; +} + } diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index b190293f..ef9fd2c7 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -339,32 +339,34 @@ void multiplyAdd(T gain, absl::Span input, absl::Span output) noexce multiplyAdd(gain, input.data(), output.data(), minSpanSize(input, output)); } -namespace _internals { - template - inline void snippetRampLinear(T*& output, T& value, T step) - { - *output++ = value; - value += step; - } -} - /** * @brief Compute a linear ramp blockwise between 2 values * * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version * @param output The destination span * @param start * @param step + * @param size * @return T */ -template +template +T linearRamp(T* output, T start, T step, unsigned size) noexcept +{ + const auto sentinel = output + size; + while (output < sentinel) { + *output++ = start; + start += step; + } + return start; +} + +template <> +float linearRamp(float* output, float start, float step, unsigned size) noexcept; + +template T linearRamp(absl::Span output, T start, T step) noexcept { - auto* out = output.begin(); - while (out < output.end()) - _internals::snippetRampLinear(out, start, step); - return start; + return linearRamp(output.data(), start, step, output.size()); } namespace _internals { @@ -380,26 +382,31 @@ namespace _internals { * @brief Compute a multiplicative ramp blockwise between 2 values * * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version * @param output The destination span * @param start * @param step * @return T */ -template -T multiplicativeRamp(absl::Span output, T start, T step) noexcept +template +T multiplicativeRamp(T* output, T start, T step, unsigned size) noexcept { - auto* out = output.begin(); - while (out < output.end()) - _internals::snippetRampMultiplicative(out, start, step); + const auto sentinel = output + size; + while (output < sentinel) { + *output++ = start; + start *= step; + } return start; } template <> -float linearRamp(absl::Span output, float start, float step) noexcept; +float multiplicativeRamp(float* output, float start, float step, unsigned size) noexcept; -template <> -float multiplicativeRamp(absl::Span output, float start, float step) noexcept; +template +T multiplicativeRamp(absl::Span output, T start, T step) noexcept +{ + return multiplicativeRamp(output.data(), start, step, output.size()); + +} namespace _internals { template diff --git a/src/sfizz/SIMDSSE.cpp b/src/sfizz/SIMDSSE.cpp index d9be6492..a1258e85 100644 --- a/src/sfizz/SIMDSSE.cpp +++ b/src/sfizz/SIMDSSE.cpp @@ -16,56 +16,7 @@ constexpr uintptr_t TypeAlignment = 4; -template <> -float sfz::linearRamp(absl::Span output, float value, float step) noexcept -{ - auto* out = output.begin(); - const auto* lastAligned = prevAligned(output.end()); - while (unaligned(out) && out < lastAligned) - _internals::snippetRampLinear(out, value, step); - - auto mmValue = _mm_set1_ps(value - step); - auto mmStep = _mm_set_ps(step + step + step + step, step + step + step, step + step, step); - - while (out < lastAligned) { - mmValue = _mm_add_ps(mmValue, mmStep); - _mm_store_ps(out, mmValue); - mmValue = _mm_shuffle_ps(mmValue, mmValue, _MM_SHUFFLE(3, 3, 3, 3)); - out += TypeAlignment; - } - - value = _mm_cvtss_f32(mmValue) + step; - - while (out < output.end()) - _internals::snippetRampLinear(out, value, step); - return value; -} - -template <> -float sfz::multiplicativeRamp(absl::Span output, float value, float step) noexcept -{ - auto* out = output.begin(); - const auto* lastAligned = prevAligned(output.end()); - - while (unaligned(out) && out < lastAligned) - _internals::snippetRampMultiplicative(out, value, step); - - auto mmValue = _mm_set1_ps(value / step); - auto mmStep = _mm_set_ps(step * step * step * step, step * step * step, step * step, step); - - while (out < lastAligned) { - mmValue = _mm_mul_ps(mmValue, mmStep); - _mm_store_ps(out, mmValue); - mmValue = _mm_shuffle_ps(mmValue, mmValue, _MM_SHUFFLE(3, 3, 3, 3)); - out += TypeAlignment; - } - - value = _mm_cvtss_f32(mmValue) * step; - while (out < output.end()) - _internals::snippetRampMultiplicative(out, value, step); - return value; -} template <> void sfz::add(absl::Span input, absl::Span output) noexcept diff --git a/tests/SIMDHelpersT.cpp b/tests/SIMDHelpersT.cpp index bd864e52..6e67ee78 100644 --- a/tests/SIMDHelpersT.cpp +++ b/tests/SIMDHelpersT.cpp @@ -356,7 +356,8 @@ TEST_CASE("[Helpers] Linear Ramp") const float v { fillValue }; std::array output; std::array expected { start, start + v, start + v + v, start + v + v + v, start + v + v + v + v, start + v + v + v + v + v }; - sfz::linearRamp(absl::MakeSpan(output), start, v); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, false); + sfz::linearRamp(absl::MakeSpan(output), start, v); REQUIRE(output == expected); } @@ -366,7 +367,8 @@ TEST_CASE("[Helpers] Linear Ramp (SIMD)") const float v { fillValue }; std::array output; std::array expected { start, start + v, start + v + v, start + v + v + v, start + v + v + v + v, start + v + v + v + v + v }; - sfz::linearRamp(absl::MakeSpan(output), start, v); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); + sfz::linearRamp(absl::MakeSpan(output), start, v); REQUIRE(approxEqual(output, expected)); } @@ -375,8 +377,10 @@ TEST_CASE("[Helpers] Linear Ramp (SIMD vs scalar)") const float start { 0.0f }; std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); - sfz::linearRamp(absl::MakeSpan(outputScalar), start, fillValue); - sfz::linearRamp(absl::MakeSpan(outputSIMD), start, fillValue); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, false); + sfz::linearRamp(absl::MakeSpan(outputScalar), start, fillValue); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); + sfz::linearRamp(absl::MakeSpan(outputSIMD), start, fillValue); REQUIRE(approxEqual(outputScalar, outputSIMD)); } @@ -385,8 +389,10 @@ TEST_CASE("[Helpers] Linear Ramp unaligned (SIMD vs scalar)") const float start { 0.0f }; std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); - sfz::linearRamp(absl::MakeSpan(outputScalar).subspan(1), start, fillValue); - sfz::linearRamp(absl::MakeSpan(outputSIMD).subspan(1), start, fillValue); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, false); + sfz::linearRamp(absl::MakeSpan(outputScalar).subspan(1), start, fillValue); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); + sfz::linearRamp(absl::MakeSpan(outputSIMD).subspan(1), start, fillValue); REQUIRE(approxEqual(outputScalar, outputSIMD)); } @@ -396,7 +402,8 @@ TEST_CASE("[Helpers] Multiplicative Ramp") const float v { fillValue }; std::array output; std::array expected { start, start * v, start * v * v, start * v * v * v, start * v * v * v * v, start * v * v * v * v * v }; - sfz::multiplicativeRamp(absl::MakeSpan(output), start, v); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, false); + sfz::multiplicativeRamp(absl::MakeSpan(output), start, v); REQUIRE(approxEqual(output, expected)); } @@ -406,7 +413,8 @@ TEST_CASE("[Helpers] Multiplicative Ramp (SIMD)") const float v { fillValue }; std::array output; std::array expected { start, start * v, start * v * v, start * v * v * v, start * v * v * v * v, start * v * v * v * v * v }; - sfz::multiplicativeRamp(absl::MakeSpan(output), start, v); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, true); + sfz::multiplicativeRamp(absl::MakeSpan(output), start, v); REQUIRE(approxEqual(output, expected)); } @@ -415,8 +423,10 @@ TEST_CASE("[Helpers] Multiplicative Ramp (SIMD vs scalar)") const float start { 1.0f }; std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); - sfz::multiplicativeRamp(absl::MakeSpan(outputScalar), start, fillValue); - sfz::multiplicativeRamp(absl::MakeSpan(outputSIMD), start, fillValue); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, false); + sfz::multiplicativeRamp(absl::MakeSpan(outputScalar), start, fillValue); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, true); + sfz::multiplicativeRamp(absl::MakeSpan(outputSIMD), start, fillValue); REQUIRE(approxEqual(outputScalar, outputSIMD)); } @@ -425,8 +435,10 @@ TEST_CASE("[Helpers] Multiplicative Ramp unaligned (SIMD vs scalar)") const float start { 1.0f }; std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); - sfz::multiplicativeRamp(absl::MakeSpan(outputScalar).subspan(1), start, fillValue); - sfz::multiplicativeRamp(absl::MakeSpan(outputSIMD).subspan(1), start, fillValue); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, false); + sfz::multiplicativeRamp(absl::MakeSpan(outputScalar).subspan(1), start, fillValue); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, true); + sfz::multiplicativeRamp(absl::MakeSpan(outputSIMD).subspan(1), start, fillValue); REQUIRE(approxEqual(outputScalar, outputSIMD)); } @@ -666,6 +678,7 @@ TEST_CASE("[Helpers] Cumulative sum (SIMD vs Scalar)") std::vector input(bigBufferSize); std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); sfz::linearRamp(absl::MakeSpan(input), 0.0f, 0.1f); sfz::cumsum(input, absl::MakeSpan(outputScalar)); sfz::cumsum(input, absl::MakeSpan(outputSIMD)); @@ -686,6 +699,7 @@ TEST_CASE("[Helpers] Diff (SIMD vs Scalar)") std::vector input(bigBufferSize); std::vector outputScalar(bigBufferSize); 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)); From 3cb816406824f00bcd8db74b6afe92ebade99619 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 31 May 2020 09:24:44 +0200 Subject: [PATCH 17/42] 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)); } From af855d39937c8432dcb0d9c00acc31732736932c Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 31 May 2020 09:31:23 +0200 Subject: [PATCH 18/42] Move subtract to the new format --- benchmarks/BM_subtract.cpp | 12 ++++-- src/sfizz/SIMDHelpers.cpp | 53 ++++++++++++++++++++++++ src/sfizz/SIMDHelpers.h | 83 +++++++++++++++++--------------------- src/sfizz/SIMDSSE.cpp | 41 ------------------- tests/SIMDHelpersT.cpp | 20 +++++---- 5 files changed, 112 insertions(+), 97 deletions(-) diff --git a/benchmarks/BM_subtract.cpp b/benchmarks/BM_subtract.cpp index afc8fc95..0bc60f15 100644 --- a/benchmarks/BM_subtract.cpp +++ b/benchmarks/BM_subtract.cpp @@ -36,28 +36,32 @@ public: BENCHMARK_DEFINE_F(SubArray, Scalar)(benchmark::State& state) { for (auto _ : state) { - sfz::subtract(input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, false); + sfz::subtract(input, absl::MakeSpan(output)); } } BENCHMARK_DEFINE_F(SubArray, SIMD)(benchmark::State& state) { for (auto _ : state) { - sfz::subtract(input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, true); + sfz::subtract(input, absl::MakeSpan(output)); } } BENCHMARK_DEFINE_F(SubArray, Scalar_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::subtract(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, false); + sfz::subtract(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } BENCHMARK_DEFINE_F(SubArray, SIMD_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::subtract(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, true); + sfz::subtract(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index 245246be..ada8cb78 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -392,4 +392,57 @@ void add(float value, float* output, unsigned size) noexcept *output++ += value; } +template <> +void subtract(const float* input, float* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + + if (getSIMDOpStatus(SIMDOps::subtract)) { +#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_sub_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 subtract(float value, float* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + + if (getSIMDOpStatus(SIMDOps::subtract)) { +#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_sub_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 24370bb0..29e36f33 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -450,63 +450,56 @@ void add(T value, absl::Span output) noexcept add(value, output.data(), output.size()); } -namespace _internals { - template - inline void snippetSubtract(const T*& input, T*& output) - { - *output++ -= *input++; - } - - template - inline void snippetSubtract(const T value, T*& output) - { - *output++ -= value; - } -} - /** - * @brief Subtract a value from a span + * @brief Subtract an input span from the output span * * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version - * @param value - * @param output - */ -template -void subtract(const T value, absl::Span output) noexcept -{ - auto* out = output.begin(); - auto* sentinel = output.end(); - while (out < sentinel) - _internals::snippetSubtract(value, out); -} - -/** - * @brief Subtract a span from another span - * - * 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 input * @param output + * @param size */ -template -void subtract(absl::Span input, absl::Span output) noexcept +template +void subtract(const T* input, T* output, unsigned size) 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::snippetSubtract(in, out); + const auto sentinel = output + size; + while (output < sentinel) + *output++ -= *input++; } template <> -void subtract(absl::Span input, absl::Span output) noexcept; +void subtract(const float* input, float* output, unsigned size) noexcept; + +template +void subtract(absl::Span input, absl::Span output) noexcept +{ + CHECK_SPAN_SIZES(input, output); + subtract(input.data(), output.data(), minSpanSize(input, output)); +} + +/** + * @brief Subtract a value inplace + * + * @tparam T the underlying type + * @param value + * @param output + * @param size + */ +template +void subtract(T value, T* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + while (output < sentinel) + *output++ -= value; +} template <> -void subtract(const float value, absl::Span output) noexcept; +void subtract(float value, float* output, unsigned size) noexcept; + +template +void subtract(T value, absl::Span output) noexcept +{ + subtract(value, output.data(), output.size()); +} namespace _internals { template diff --git a/src/sfizz/SIMDSSE.cpp b/src/sfizz/SIMDSSE.cpp index aca877a6..0a4422e4 100644 --- a/src/sfizz/SIMDSSE.cpp +++ b/src/sfizz/SIMDSSE.cpp @@ -16,47 +16,6 @@ constexpr uintptr_t TypeAlignment = 4; -template <> -void sfz::subtract(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::snippetSubtract(in, out); - - while (out < lastAligned) { - _mm_store_ps(out, _mm_sub_ps(_mm_load_ps(out), _mm_load_ps(in))); - incrementAll(in, out); - } - - while (out < sentinel) - _internals::snippetSubtract(in, out); -} - -template <> -void sfz::subtract(const 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::snippetSubtract(value, out); - - auto mmValue = _mm_set_ps1(value); - while (out < lastAligned) { - _mm_store_ps(out, _mm_sub_ps(_mm_load_ps(out), mmValue)); - out += TypeAlignment; - } - - while (out < sentinel) - _internals::snippetSubtract(value, out); -} - template <> void sfz::copy(absl::Span input, absl::Span output) noexcept { diff --git a/tests/SIMDHelpersT.cpp b/tests/SIMDHelpersT.cpp index b38774f3..5d35ce89 100644 --- a/tests/SIMDHelpersT.cpp +++ b/tests/SIMDHelpersT.cpp @@ -562,7 +562,7 @@ TEST_CASE("[Helpers] Subtract") 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 { 0.0f, -1.0f, -2.0f, -3.0f, -4.0f }; - sfz::subtract(input, absl::MakeSpan(output)); + sfz::subtract(input, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -570,7 +570,8 @@ TEST_CASE("[Helpers] Subtract 2") { std::array output { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array expected { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f }; - sfz::subtract(1.0f, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, false); + sfz::subtract(1.0f, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -580,7 +581,8 @@ TEST_CASE("[Helpers] Subtract (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 { 0.0f, -1.0f, -2.0f, -3.0f, -4.0f }; - sfz::subtract(input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, true); + sfz::subtract(input, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -593,8 +595,10 @@ TEST_CASE("[Helpers] Subtract (SIMD vs scalar)") absl::c_fill(outputScalar, 0.0f); absl::c_fill(outputSIMD, 0.0f); - sfz::subtract(input, absl::MakeSpan(outputScalar)); - sfz::subtract(input, absl::MakeSpan(outputSIMD)); + sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, false); + sfz::subtract(input, absl::MakeSpan(outputScalar)); + sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, true); + sfz::subtract(input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } @@ -605,8 +609,10 @@ TEST_CASE("[Helpers] Subtract 2 (SIMD vs scalar)") absl::c_iota(outputScalar, 0.0f); absl::c_iota(outputSIMD, 0.0f); - sfz::subtract(1.2f, absl::MakeSpan(outputScalar)); - sfz::subtract(1.2f, absl::MakeSpan(outputSIMD)); + sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, false); + sfz::subtract(1.2f, absl::MakeSpan(outputScalar)); + sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, true); + sfz::subtract(1.2f, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } From 190e7085de4eea97d8bb2c1848ccc860251f53e5 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 31 May 2020 09:49:28 +0200 Subject: [PATCH 19/42] Move copy to the new format --- benchmarks/BM_copy.cpp | 12 ++++++++---- src/sfizz/SIMDHelpers.cpp | 26 ++++++++++++++++++++++++++ src/sfizz/SIMDHelpers.h | 34 ++++++++++++---------------------- src/sfizz/SIMDSSE.cpp | 21 --------------------- tests/SIMDHelpersT.cpp | 12 ++++++++---- 5 files changed, 54 insertions(+), 51 deletions(-) diff --git a/benchmarks/BM_copy.cpp b/benchmarks/BM_copy.cpp index 20d4f088..1196730b 100644 --- a/benchmarks/BM_copy.cpp +++ b/benchmarks/BM_copy.cpp @@ -43,14 +43,16 @@ BENCHMARK_DEFINE_F(CopyArray, StdCopy)(benchmark::State& state) { BENCHMARK_DEFINE_F(CopyArray, Scalar)(benchmark::State& state) { for (auto _ : state) { - sfz::copy(input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::copy, false); + sfz::copy(input, absl::MakeSpan(output)); } } BENCHMARK_DEFINE_F(CopyArray, SIMD)(benchmark::State& state) { for (auto _ : state) { - sfz::copy(input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::copy, true); + sfz::copy(input, absl::MakeSpan(output)); } } @@ -64,14 +66,16 @@ BENCHMARK_DEFINE_F(CopyArray, StdCopy_Unaligned)(benchmark::State& state) { BENCHMARK_DEFINE_F(CopyArray, Scalar_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::copy(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::copy, false); + sfz::copy(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } BENCHMARK_DEFINE_F(CopyArray, SIMD_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::copy(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::copy, true); + sfz::copy(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index ada8cb78..d1c61bdc 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -445,4 +445,30 @@ void subtract(float value, float* output, unsigned size) noexcept *output++ -= value; } +template <> +void copy(const float* input, float* output, unsigned size) noexcept +{ + // The sentinel is the input here + const auto sentinel = input + size; + + if (getSIMDOpStatus(SIMDOps::copy)) { +#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 + if (cpuInfo.has_sse()) { + const auto* lastAligned = prevAligned(sentinel); + + while (unaligned(input, output) && input < lastAligned) + *output++ = *input++; + + while (input < lastAligned) { + _mm_store_ps(output, _mm_load_ps(input)); + incrementAll<4>(input, output); + } + // fallthrough from lastAligned to sentinel + } +#endif + } + + std::copy(input, sentinel, output); +} + } diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index 29e36f33..aef54af6 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -501,39 +501,29 @@ void subtract(T value, absl::Span output) noexcept subtract(value, output.data(), output.size()); } -namespace _internals { - template - void snippetCopy(const T*& input, T*& output) - { - *output++ = *input++; - } -} - /** * @brief Copy a span in another * - * 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 input * @param output + * @param size */ -template -void copy(absl::Span input, absl::Span output) noexcept +template +void copy(const T* input, T* output, unsigned size) noexcept { - CHECK(output.size() >= input.size()); - if (output.data() == input.data() && output.size() == input.size()) - return; - auto* in = input.begin(); - auto* out = output.begin(); - auto* sentinel = out + min(input.size(), output.size()); - while (out < sentinel) - _internals::snippetCopy(in, out); + std::copy(input, input + size, output); } template <> -void copy(absl::Span input, absl::Span output) noexcept; +void copy(const float* input, float* output, unsigned size) noexcept; + +template +void copy(absl::Span input, absl::Span output) noexcept +{ + CHECK_SPAN_SIZES(input, output); + copy(input.data(), output.data(), minSpanSize(input, output)); +} namespace _internals { // Number of elements in the table, odd for equal volume at center diff --git a/src/sfizz/SIMDSSE.cpp b/src/sfizz/SIMDSSE.cpp index 0a4422e4..da6a734b 100644 --- a/src/sfizz/SIMDSSE.cpp +++ b/src/sfizz/SIMDSSE.cpp @@ -16,27 +16,6 @@ constexpr uintptr_t TypeAlignment = 4; -template <> -void sfz::copy(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::snippetCopy(in, out); - - while (out < lastAligned) { - _mm_store_ps(out, _mm_load_ps(in)); - incrementAll(in, out); - } - - while (out < sentinel) - _internals::snippetCopy(in, out); -} - template <> void sfz::pan(absl::Span panEnvelope, absl::Span leftBuffer, absl::Span rightBuffer) noexcept { diff --git a/tests/SIMDHelpersT.cpp b/tests/SIMDHelpersT.cpp index 5d35ce89..d4d3c437 100644 --- a/tests/SIMDHelpersT.cpp +++ b/tests/SIMDHelpersT.cpp @@ -620,7 +620,8 @@ TEST_CASE("[Helpers] copy") { 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 }; - sfz::copy(input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::copy, false); + sfz::copy(input, absl::MakeSpan(output)); REQUIRE(output == input); } @@ -628,7 +629,8 @@ TEST_CASE("[Helpers] copy (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 }; - sfz::copy(input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::copy, true); + sfz::copy(input, absl::MakeSpan(output)); REQUIRE(output == input); } @@ -641,8 +643,10 @@ TEST_CASE("[Helpers] copy (SIMD vs scalar)") absl::c_fill(outputScalar, 0.0f); absl::c_fill(outputSIMD, 0.0f); - sfz::copy(input, absl::MakeSpan(outputScalar)); - sfz::copy(input, absl::MakeSpan(outputSIMD)); + sfz::setSIMDOpStatus(sfz::SIMDOps::copy, false); + sfz::copy(input, absl::MakeSpan(outputScalar)); + sfz::setSIMDOpStatus(sfz::SIMDOps::copy, true); + sfz::copy(input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } From cebf9060e1195d6888099e2566932725e6c1f548 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 31 May 2020 10:31:03 +0200 Subject: [PATCH 20/42] Move panning into its own file and outside of SIMD --- benchmarks/BM_pan.cpp | 68 ---------------------- benchmarks/BM_widthPos.cpp | 80 -------------------------- benchmarks/CMakeLists.txt | 2 - dpf.mk | 1 + scripts/run_clang_tidy.sh | 1 + src/CMakeLists.txt | 1 + src/sfizz/MathHelpers.h | 1 + src/sfizz/Panning.cpp | 58 +++++++++++++++++++ src/sfizz/Panning.h | 47 ++++++++++++++++ src/sfizz/SIMDHelpers.h | 109 ------------------------------------ src/sfizz/SIMDSSE.cpp | 79 -------------------------- src/sfizz/SfzHelpers.cpp | 14 +++-- src/sfizz/Voice.cpp | 9 +-- src/sfizz/effects/Width.cpp | 6 +- tests/DemoStereo.cpp | 6 +- tests/SIMDHelpersT.cpp | 13 +++-- 16 files changed, 136 insertions(+), 359 deletions(-) delete mode 100644 benchmarks/BM_pan.cpp delete mode 100644 benchmarks/BM_widthPos.cpp create mode 100644 src/sfizz/Panning.cpp create mode 100644 src/sfizz/Panning.h diff --git a/benchmarks/BM_pan.cpp b/benchmarks/BM_pan.cpp deleted file mode 100644 index e08b447e..00000000 --- a/benchmarks/BM_pan.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause - -// This code is part of the sfizz library and is licensed under a BSD 2-clause -// license. You should have receive a LICENSE.md file along with the code. -// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz - -#include "SIMDHelpers.h" -#include -#include -#include -#include -#include -#include -#include "Config.h" -#include "ScopedFTZ.h" -#include "absl/types/span.h" - -class PanArray : public benchmark::Fixture { -public: - void SetUp(const ::benchmark::State& state) { - std::random_device rd { }; - std::mt19937 gen { rd() }; - std::uniform_real_distribution dist { 0.001f, 1.0f }; - pan = std::vector(state.range(0)); - left = std::vector(state.range(0)); - right = std::vector(state.range(0)); - std::generate(pan.begin(), pan.end(), [&]() { return dist(gen); }); - std::generate(right.begin(), right.end(), [&]() { return dist(gen); }); - std::generate(left.begin(), left.end(), [&]() { return dist(gen); }); - temp1 = std::vector(state.range(0)); - temp2 = std::vector(state.range(0)); - span1 = absl::MakeSpan(temp1); - span2 = absl::MakeSpan(temp2); - } - - void TearDown(const ::benchmark::State& /* state */) { - - } - - std::vector pan; - std::vector left; - std::vector right; - std::vector temp1; - std::vector temp2; - absl::Span span1; - absl::Span span2; -}; - - -BENCHMARK_DEFINE_F(PanArray, Scalar)(benchmark::State& state) { - ScopedFTZ ftz; - for (auto _ : state) - { - sfz::pan(pan, absl::MakeSpan(left), absl::MakeSpan(right)); - } -} - -BENCHMARK_DEFINE_F(PanArray, SIMD)(benchmark::State& state) { - ScopedFTZ ftz; - for (auto _ : state) - { - sfz::pan(pan, absl::MakeSpan(left), absl::MakeSpan(right)); - } -} - -BENCHMARK_REGISTER_F(PanArray, Scalar)->RangeMultiplier(4)->Range(1 << 2, 1 << 12); -BENCHMARK_REGISTER_F(PanArray, SIMD)->RangeMultiplier(4)->Range(1 << 2, 1 << 12); -BENCHMARK_MAIN(); diff --git a/benchmarks/BM_widthPos.cpp b/benchmarks/BM_widthPos.cpp deleted file mode 100644 index 1ab9fa7d..00000000 --- a/benchmarks/BM_widthPos.cpp +++ /dev/null @@ -1,80 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause - -// This code is part of the sfizz library and is licensed under a BSD 2-clause -// license. You should have receive a LICENSE.md file along with the code. -// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz - -#include "SIMDHelpers.h" -#include -#include -#include -#include -#include -#include -#include "Config.h" -#include "ScopedFTZ.h" -#include "absl/types/span.h" - -class WidthPosArray : public benchmark::Fixture { -public: - void SetUp(const ::benchmark::State& state) { - std::random_device rd { }; - std::mt19937 gen { rd() }; - std::uniform_real_distribution dist { 0.001f, 1.0f }; - width = std::vector(state.range(0)); - position = std::vector(state.range(0)); - left = std::vector(state.range(0)); - right = std::vector(state.range(0)); - std::generate(width.begin(), width.end(), [&]() { return dist(gen); }); - std::generate(position.begin(), position.end(), [&]() { return dist(gen); }); - std::generate(right.begin(), right.end(), [&]() { return dist(gen); }); - std::generate(left.begin(), left.end(), [&]() { return dist(gen); }); - temp1 = std::vector(state.range(0)); - temp2 = std::vector(state.range(0)); - temp3 = std::vector(state.range(0)); - span1 = absl::MakeSpan(temp1); - span2 = absl::MakeSpan(temp2); - span3 = absl::MakeSpan(temp3); - } - - void TearDown(const ::benchmark::State& /* state */) { - - } - - std::vector width; - std::vector position; - std::vector left; - std::vector right; - std::vector temp1; - std::vector temp2; - std::vector temp3; - absl::Span span1; - absl::Span span2; - absl::Span span3; -}; - -BENCHMARK_DEFINE_F(WidthPosArray, Scalar)(benchmark::State& state) { - ScopedFTZ ftz; - const auto leftBuffer = absl::MakeSpan(left); - const auto rightBuffer = absl::MakeSpan(right); - for (auto _ : state) - { - sfz::width(width, leftBuffer, rightBuffer); - sfz::pan(position, leftBuffer, rightBuffer); - } -} - -BENCHMARK_DEFINE_F(WidthPosArray, SIMD)(benchmark::State& state) { - ScopedFTZ ftz; - const auto leftBuffer = absl::MakeSpan(left); - const auto rightBuffer = absl::MakeSpan(right); - for (auto _ : state) - { - sfz::width(width, leftBuffer, rightBuffer); - sfz::pan(position, leftBuffer, rightBuffer); - } -} - -BENCHMARK_REGISTER_F(WidthPosArray, Scalar)->RangeMultiplier(4)->Range(1 << 2, 1 << 12); -BENCHMARK_REGISTER_F(WidthPosArray, SIMD)->RangeMultiplier(4)->Range(1 << 2, 1 << 12); -BENCHMARK_MAIN(); diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 0fa42459..0e44d964 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -50,12 +50,10 @@ sfizz_add_benchmark(bm_multiplyAdd BM_multiplyAdd.cpp) sfizz_add_benchmark(bm_multiplyAddFixedGain BM_multiplyAddFixedGain.cpp) sfizz_add_benchmark(bm_subtract BM_subtract.cpp) sfizz_add_benchmark(bm_copy BM_copy.cpp) -sfizz_add_benchmark(bm_pan BM_pan.cpp) sfizz_add_benchmark(bm_mean BM_mean.cpp) sfizz_add_benchmark(bm_meanSquared BM_meanSquared.cpp) sfizz_add_benchmark(bm_cumsum BM_cumsum.cpp) sfizz_add_benchmark(bm_diff BM_diff.cpp) -sfizz_add_benchmark(bm_widthPos BM_widthPos.cpp) sfizz_add_benchmark(bm_interpolationCast BM_interpolationCast.cpp) sfizz_add_benchmark(bm_pointerIterationOrOffsets BM_pointerIterationOrOffsets.cpp) sfizz_add_benchmark(bm_maps BM_maps.cpp) diff --git a/dpf.mk b/dpf.mk index c02c2f0e..a2734283 100644 --- a/dpf.mk +++ b/dpf.mk @@ -85,6 +85,7 @@ SFIZZ_SOURCES = \ src/sfizz/OpcodeCleanup.cpp \ src/sfizz/Opcode.cpp \ src/sfizz/Oversampler.cpp \ + src/sfizz/Panning.cpp \ src/sfizz/Parser.cpp \ src/sfizz/parser/Parser.cpp \ src/sfizz/parser/ParserPrivate.cpp \ diff --git a/scripts/run_clang_tidy.sh b/scripts/run_clang_tidy.sh index a58587b8..6c1f6f8a 100755 --- a/scripts/run_clang_tidy.sh +++ b/scripts/run_clang_tidy.sh @@ -13,6 +13,7 @@ clang-tidy \ src/sfizz/Opcode.cpp \ src/sfizz/Oversampler.cpp \ src/sfizz/Parser.cpp \ + src/sfizz/Panning.cpp \ src/sfizz/sfizz.cpp \ src/sfizz/Region.cpp \ src/sfizz/SfzHelpers.cpp \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0307417f..a75f96db 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,6 +23,7 @@ set (SFIZZ_SOURCES sfizz/Wavetables.cpp sfizz/Tuning.cpp sfizz/RTSemaphore.cpp + sfizz/Panning.cpp sfizz/Effects.cpp sfizz/effects/Nothing.cpp sfizz/effects/Filter.cpp diff --git a/src/sfizz/MathHelpers.h b/src/sfizz/MathHelpers.h index 3bb10f67..cf30c79a 100644 --- a/src/sfizz/MathHelpers.h +++ b/src/sfizz/MathHelpers.h @@ -9,6 +9,7 @@ * @brief Contains math helper functions and math constants */ #pragma once +#include "Debug.h" #include "Config.h" #include "Macros.h" #include "SIMDConfig.h" diff --git a/src/sfizz/Panning.cpp b/src/sfizz/Panning.cpp new file mode 100644 index 00000000..bdafebd8 --- /dev/null +++ b/src/sfizz/Panning.cpp @@ -0,0 +1,58 @@ +#include "Panning.h" +#include + +namespace sfz +{ +// Number of elements in the table, odd for equal volume at center +constexpr int panSize = 4095; + +// Table of pan values for the left channel, extra element for safety +static const auto panData = []() +{ + std::array pan; + int i = 0; + + for (; i < panSize; ++i) + pan[i] = std::cos(i * (piTwo() / (panSize - 1))); + + for (; i < static_cast(pan.size()); ++i) + pan[i] = pan[panSize - 1]; + + return pan; +}(); + +float panLookup(float pan) +{ + // reduce range, round to nearest + int index = static_cast(0.5f + pan * (panSize - 1)); + return panData[index]; +} + +void pan(const float* panEnvelope, float* leftBuffer, float* rightBuffer, unsigned size) noexcept +{ + const auto sentinel = panEnvelope + size; + while (panEnvelope < sentinel) { + auto p =(*panEnvelope + 1.0f) * 0.5f; + p = clamp(p, 0.0f, 1.0f); + *leftBuffer *= panLookup(p); + *rightBuffer *= panLookup(1 - p); + incrementAll(panEnvelope, leftBuffer, rightBuffer); + } +} + +void width(const float* widthEnvelope, float* leftBuffer, float* rightBuffer, unsigned size) noexcept +{ + const auto sentinel = widthEnvelope + size; + while (widthEnvelope < sentinel) { + float w = (*widthEnvelope + 1.0f) * 0.5f; + w = clamp(w, 0.0f, 1.0f); + const auto coeff1 = panLookup(w); + const auto coeff2 = panLookup(1 - w); + const auto l = *leftBuffer; + const auto r = *rightBuffer; + *leftBuffer = l * coeff2 + r * coeff1; + *rightBuffer = l * coeff1 + r * coeff2; + incrementAll(widthEnvelope, leftBuffer, rightBuffer); + } +} +} diff --git a/src/sfizz/Panning.h b/src/sfizz/Panning.h new file mode 100644 index 00000000..75d31ea4 --- /dev/null +++ b/src/sfizz/Panning.h @@ -0,0 +1,47 @@ +#pragma once +#include "absl/types/span.h" +#include "MathHelpers.h" + +namespace sfz +{ + +/** + * @brief Lookup a value from the pan table + * + * @param pan + * @return float + */ +float panLookup(float pan); + +/** + * @brief Pans a mono signal left or right + * + * @param panEnvelope + * @param leftBuffer + * @param rightBuffer + * @param size + */ +void pan(const float* panEnvelope, float* leftBuffer, float* rightBuffer, unsigned size) noexcept; +inline void pan(absl::Span panEnvelope, absl::Span leftBuffer, absl::Span rightBuffer) noexcept +{ + CHECK_SPAN_SIZES(panEnvelope, leftBuffer, rightBuffer); + pan(panEnvelope.data(), leftBuffer.data(), rightBuffer.data(), minSpanSize(panEnvelope, leftBuffer, rightBuffer)); +} + +/** + * @brief Controls the width of a stereo signal, setting it to mono when width = 0 and inverting the channels + * when width = -1. Width = 1 has no effect. + * + * @param widthEnvelope + * @param leftBuffer + * @param rightBuffer + * @param size + */ +void width(const float* widthEnvelope, float* leftBuffer, float* rightBuffer, unsigned size) noexcept; +inline void width(absl::Span widthEnvelope, absl::Span leftBuffer, absl::Span rightBuffer) noexcept +{ + CHECK_SPAN_SIZES(widthEnvelope, leftBuffer, rightBuffer); + width(widthEnvelope.data(), leftBuffer.data(), rightBuffer.data(), minSpanSize(widthEnvelope, leftBuffer, rightBuffer)); +} + +} diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index aef54af6..1f2ab5e3 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -525,115 +525,6 @@ void copy(absl::Span input, absl::Span output) noexcept copy(input.data(), output.data(), minSpanSize(input, output)); } -namespace _internals { - // Number of elements in the table, odd for equal volume at center - constexpr int panSize = 4095; - - // Table of pan values for the left channel, extra element for safety - const auto panData = []() - { - std::array pan; - int i = 0; - - for (; i < panSize; ++i) - pan[i] = std::cos(i * (piTwo() / (panSize - 1))); - - for (; i < static_cast(pan.size()); ++i) - pan[i] = pan[panSize - 1]; - - return pan; - }(); - - template - inline T panLookup(T pan) - { - // reduce range, round to nearest - int index = static_cast(T{0.5} + pan * (panSize - 1)); - return panData[index]; - } - - template - inline void snippetPan(T pan, T& left, T& right) - { - pan = (pan + T{1.0}) * T{0.5}; - pan = clamp(pan, 0, 1); - left *= panLookup(pan); - right *= panLookup(1 - pan); - } - - template - inline void snippetWidth(T width, T& left, T& right) - { - T w = (width + T{1.0}) * T{0.5}; - w = clamp(w, 0, 1); - const auto coeff1 = panLookup(w); - const auto coeff2 = panLookup(1 - w); - const auto l = left; - const auto r = right; - left = l * coeff2 + r * coeff1; - right = l * coeff1 + r * coeff2; - } -} - -/** - * @brief Pans a mono signal left or right - * - * The output size will be the minimum of the pan envelope span and left and right buffer span sizes. - * - * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version - * @param panEnvelope - * @param leftBuffer - * @param rightBuffer - */ -template -void pan(absl::Span panEnvelope, absl::Span leftBuffer, absl::Span rightBuffer) noexcept -{ - CHECK(leftBuffer.size() >= panEnvelope.size()); - CHECK(rightBuffer.size() >= panEnvelope.size()); - auto* pan = panEnvelope.begin(); - auto* left = leftBuffer.begin(); - auto* right = rightBuffer.begin(); - auto* sentinel = pan + min(panEnvelope.size(), leftBuffer.size(), rightBuffer.size()); - while (pan < sentinel) { - _internals::snippetPan(*pan, *left, *right); - incrementAll(pan, left, right); - } -} - -template <> -void pan(absl::Span panEnvelope, absl::Span leftBuffer, absl::Span rightBuffer) noexcept; - -/** - * @brief Controls the width of a stereo signal, setting it to mono when width = 0 and inverting the channels - * when width = -1. Width = 1 has no effect. - * - * The output size will be the minimum of the width envelope span and left and right buffer span sizes. - * - * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version - * @param panEnvelope - * @param leftBuffer - * @param rightBuffer - */ -template -void width(absl::Span widthEnvelope, absl::Span leftBuffer, absl::Span rightBuffer) noexcept -{ - CHECK(leftBuffer.size() >= widthEnvelope.size()); - CHECK(rightBuffer.size() >= widthEnvelope.size()); - auto* width = widthEnvelope.begin(); - auto* left = leftBuffer.begin(); - auto* right = rightBuffer.begin(); - auto* sentinel = width + min(widthEnvelope.size(), leftBuffer.size(), rightBuffer.size()); - while (width < sentinel) { - _internals::snippetWidth(*width, *left, *right); - incrementAll(width, left, right); - } -} - -template <> -void width(absl::Span widthEnvelope, absl::Span leftBuffer, absl::Span rightBuffer) noexcept; - /** * @brief Computes the mean of a span * diff --git a/src/sfizz/SIMDSSE.cpp b/src/sfizz/SIMDSSE.cpp index da6a734b..f20938b7 100644 --- a/src/sfizz/SIMDSSE.cpp +++ b/src/sfizz/SIMDSSE.cpp @@ -16,85 +16,6 @@ constexpr uintptr_t TypeAlignment = 4; -template <> -void sfz::pan(absl::Span panEnvelope, absl::Span leftBuffer, absl::Span rightBuffer) noexcept -{ - CHECK(leftBuffer.size() >= panEnvelope.size()); - CHECK(rightBuffer.size() >= panEnvelope.size()); - auto* pan = panEnvelope.begin(); - auto* left = leftBuffer.begin(); - auto* right = rightBuffer.begin(); - auto* sentinel = pan + min(panEnvelope.size(), leftBuffer.size(), rightBuffer.size()); - const auto* lastAligned = prevAligned(sentinel); - - while (unaligned(pan, left, right) && pan < lastAligned) { - _internals::snippetPan(*pan, *left, *right); - incrementAll(pan, left, right); - } - - const auto mmOne = _mm_set_ps1(1.0f); - const auto mmPiFour = _mm_set_ps1(piFour()); - __m128 mmCos; - __m128 mmSin; - while (pan < lastAligned) { - auto mmPan = _mm_load_ps(pan); - mmPan = _mm_add_ps(mmOne, mmPan); - mmPan = _mm_mul_ps(mmPan, mmPiFour); - sincos_ps(mmPan, &mmSin, &mmCos); - auto mmLeft = _mm_mul_ps(mmCos, _mm_load_ps(left)); - auto mmRight = _mm_mul_ps(mmSin, _mm_load_ps(right)); - _mm_store_ps(left, mmLeft); - _mm_store_ps(right, mmRight); - incrementAll(pan, left, right); - } - - while (pan < sentinel){ - _internals::snippetPan(*pan, *left, *right); - incrementAll(pan, left, right); - } -} - -template <> -void sfz::width(absl::Span widthEnvelope, absl::Span leftBuffer, absl::Span rightBuffer) noexcept -{ - CHECK(leftBuffer.size() >= widthEnvelope.size()); - CHECK(rightBuffer.size() >= widthEnvelope.size()); - auto* width = widthEnvelope.begin(); - auto* left = leftBuffer.begin(); - auto* right = rightBuffer.begin(); - auto* sentinel = width + min(widthEnvelope.size(), leftBuffer.size(), rightBuffer.size()); - const auto* lastAligned = prevAligned(sentinel); - - while (unaligned(width, left, right) && width < lastAligned) { - _internals::snippetWidth(*width, *left, *right); - incrementAll(width, left, right); - } - - const auto mmPiFour = _mm_set_ps1(piFour()); - __m128 mmCos; - __m128 mmSin; - while (width < lastAligned) { - auto mmWidth = _mm_load_ps(width); - mmWidth = _mm_mul_ps(mmWidth, mmPiFour); - sincos_ps(mmWidth, &mmSin, &mmCos); - auto mmCosPlusSine = _mm_add_ps(mmCos, mmSin); - auto mmCosMinusSine = _mm_sub_ps(mmCos, mmSin); - auto mmLeft = _mm_load_ps(left); - auto mmRight = _mm_load_ps(right); - auto mmTemp = _mm_mul_ps(mmCosMinusSine, mmRight); - mmRight = _mm_add_ps(_mm_mul_ps(mmCosMinusSine, mmLeft), _mm_mul_ps(mmCosPlusSine, mmRight)); - mmLeft = _mm_add_ps(_mm_mul_ps(mmCosPlusSine, mmLeft), mmTemp); - _mm_store_ps(left, mmLeft); - _mm_store_ps(right, mmRight); - incrementAll(width, left, right); - } - - while (width < sentinel){ - _internals::snippetWidth(*width, *left, *right); - incrementAll(width, left, right); - } -} - template <> float sfz::mean(absl::Span vector) noexcept { diff --git a/src/sfizz/SfzHelpers.cpp b/src/sfizz/SfzHelpers.cpp index 435ae30d..92d64cfa 100644 --- a/src/sfizz/SfzHelpers.cpp +++ b/src/sfizz/SfzHelpers.cpp @@ -7,7 +7,9 @@ #include "SfzHelpers.h" #include "StringViewHelpers.h" -absl::optional sfz::readNoteValue(const absl::string_view& value) +namespace sfz{ + +absl::optional readNoteValue(const absl::string_view& value) { switch(hash(value)) { @@ -153,7 +155,7 @@ absl::optional sfz::readNoteValue(const absl::string_view& value) } } -bool sfz::findHeader(absl::string_view& source, absl::string_view& header, absl::string_view& members) +bool findHeader(absl::string_view& source, absl::string_view& header, absl::string_view& members) { auto openHeader = source.find("<"); if (openHeader == absl::string_view::npos) @@ -176,7 +178,7 @@ bool sfz::findHeader(absl::string_view& source, absl::string_view& header, absl: return true; } -bool sfz::findOpcode(absl::string_view& source, absl::string_view& opcode, absl::string_view& value) +bool findOpcode(absl::string_view& source, absl::string_view& opcode, absl::string_view& value) { auto opcodeEnd = source.find("="); if (opcodeEnd == absl::string_view::npos) @@ -203,7 +205,7 @@ bool sfz::findOpcode(absl::string_view& source, absl::string_view& opcode, absl: } -bool sfz::findDefine(absl::string_view line, absl::string_view& variable, absl::string_view& value) +bool findDefine(absl::string_view line, absl::string_view& variable, absl::string_view& value) { const auto defPosition = line.find("#define"); if (defPosition == absl::string_view::npos) @@ -229,7 +231,7 @@ bool sfz::findDefine(absl::string_view line, absl::string_view& variable, absl:: return true; } -bool sfz::findInclude(absl::string_view line, std::string& path) +bool findInclude(absl::string_view line, std::string& path) { const auto defPosition = line.find("#include"); if (defPosition == absl::string_view::npos) @@ -246,3 +248,5 @@ bool sfz::findInclude(absl::string_view line, std::string& path) path = std::string(line.substr(pathStart + 1, pathEnd - pathStart - 1)); return true; } + +} diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index adca60c1..597b986b 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -10,6 +10,7 @@ #include "ModifierHelpers.h" #include "MathHelpers.h" #include "SIMDHelpers.h" +#include "Panning.h" #include "SfzHelpers.h" #include "Interpolators.h" #include "absl/algorithm/container.h" @@ -363,7 +364,7 @@ void sfz::Voice::panStageMono(AudioSpan buffer) noexcept linearModifier(resources, *tempSpan, mod, normalizePercents); add(*tempSpan, *modulationSpan); } - pan(*modulationSpan, leftBuffer, rightBuffer); + pan(*modulationSpan, leftBuffer, rightBuffer); } void sfz::Voice::panStageStereo(AudioSpan buffer) noexcept @@ -384,7 +385,7 @@ void sfz::Voice::panStageStereo(AudioSpan buffer) noexcept linearModifier(resources, *tempSpan, mod, normalizePercents); add(*tempSpan, *modulationSpan); } - pan(*modulationSpan, leftBuffer, rightBuffer); + pan(*modulationSpan, leftBuffer, rightBuffer); // Apply the width/position process fill(*modulationSpan, region->width); @@ -392,14 +393,14 @@ void sfz::Voice::panStageStereo(AudioSpan buffer) noexcept linearModifier(resources, *tempSpan, mod, normalizePercents); add(*tempSpan, *modulationSpan); } - width(*modulationSpan, leftBuffer, rightBuffer); + width(*modulationSpan, leftBuffer, rightBuffer); fill(*modulationSpan, region->position); for (const auto& mod : region->positionCC) { linearModifier(resources, *tempSpan, mod, normalizePercents); add(*tempSpan, *modulationSpan); } - pan(*modulationSpan, leftBuffer, rightBuffer); + pan(*modulationSpan, leftBuffer, rightBuffer); } void sfz::Voice::filterStageMono(AudioSpan buffer) noexcept diff --git a/src/sfizz/effects/Width.cpp b/src/sfizz/effects/Width.cpp index 8c3893ff..f07a9025 100644 --- a/src/sfizz/effects/Width.cpp +++ b/src/sfizz/effects/Width.cpp @@ -16,7 +16,7 @@ #include "Width.h" #include "Opcode.h" -#include "SIMDHelpers.h" +#include "Panning.h" #include "absl/memory/memory.h" namespace sfz { @@ -53,8 +53,8 @@ namespace fx { const float r = input2[i]; const float w = clamp((widths[i] + 100.0f) * 0.005f, 0.0f, 1.0f); - const float coeff1 = _internals::panLookup(w); - const float coeff2 = _internals::panLookup(1.0f - w); + const float coeff1 = panLookup(w); + const float coeff2 = panLookup(1.0f - w); output1[i] = l * coeff2 + r * coeff1; output2[i] = l * coeff1 + r * coeff2; diff --git a/tests/DemoStereo.cpp b/tests/DemoStereo.cpp index 2ef1558c..64bc1b97 100644 --- a/tests/DemoStereo.cpp +++ b/tests/DemoStereo.cpp @@ -4,7 +4,7 @@ // license. You should have receive a LICENSE.md file along with the code. // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz -#include "sfizz/SIMDHelpers.h" +#include "sfizz/Panning.h" #include "ui_DemoStereo.h" #include #include @@ -160,8 +160,8 @@ int DemoApp::processAudio(jack_nframes_t nframes, void *cbdata) std::fill(positionEnvelope.begin(), positionEnvelope.end(), self->fPan * 0.01f); using namespace sfz; - width(widthEnvelope, leftBuffer, rightBuffer); - pan(positionEnvelope, leftBuffer, rightBuffer); + width(widthEnvelope, leftBuffer, rightBuffer); + pan(positionEnvelope, leftBuffer, rightBuffer); return 0; } diff --git a/tests/SIMDHelpersT.cpp b/tests/SIMDHelpersT.cpp index d4d3c437..fd545249 100644 --- a/tests/SIMDHelpersT.cpp +++ b/tests/SIMDHelpersT.cpp @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "sfizz/SIMDHelpers.h" +#include "sfizz/Panning.h" #include "catch2/catch.hpp" #include #include @@ -729,21 +730,21 @@ TEST_CASE("[Helpers] Pan Scalar") SECTION("Pan = 0") { std::array pan { 0.0f }; - sfz::pan(pan, left, right); + sfz::pan(pan, left, right); REQUIRE(left[0] == Approx(0.70711f).margin(0.001f)); REQUIRE(right[0] == Approx(0.70711f).margin(0.001f)); } SECTION("Pan = 1") { std::array pan { 1.0f }; - sfz::pan(pan, left, right); + sfz::pan(pan, left, right); REQUIRE(left[0] == Approx(0.0f).margin(0.001f)); REQUIRE(right[0] == Approx(1.0f).margin(0.001f)); } SECTION("Pan = -1") { std::array pan { -1.0f }; - sfz::pan(pan, left, right); + sfz::pan(pan, left, right); REQUIRE(left[0] == Approx(1.0f).margin(0.001f)); REQUIRE(right[0] == Approx(0.0f).margin(0.001f)); } @@ -758,21 +759,21 @@ TEST_CASE("[Helpers] Width Scalar") SECTION("width = 1") { std::array width { 1.0f }; - sfz::width(width, left, right); + sfz::width(width, left, right); REQUIRE(left[0] == Approx(1.0f).margin(0.001f)); REQUIRE(right[0] == Approx(1.0f).margin(0.001f)); } SECTION("width = 0") { std::array width { 0.0f }; - sfz::width(width, left, right); + sfz::width(width, left, right); REQUIRE(left[0] == Approx(1.414f).margin(0.001f)); REQUIRE(right[0] == Approx(1.414f).margin(0.001f)); } SECTION("width = -1") { std::array width { -1.0f }; - sfz::width(width, left, right); + sfz::width(width, left, right); REQUIRE(left[0] == Approx(1.0f).margin(0.001f)); REQUIRE(right[0] == Approx(1.0f).margin(0.001f)); } From 8d2ac8ebd55f9c0b7e5aaccbdc4806dc335a7211 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 31 May 2020 10:36:47 +0200 Subject: [PATCH 21/42] Prep for removing sfzInterpolationCast --- benchmarks/BM_interpolationCast.cpp | 74 ----------------------------- benchmarks/CMakeLists.txt | 1 - src/sfizz/SIMDHelpers.h | 8 ++-- src/sfizz/SIMDSSE.cpp | 30 ------------ 4 files changed, 3 insertions(+), 110 deletions(-) delete mode 100644 benchmarks/BM_interpolationCast.cpp diff --git a/benchmarks/BM_interpolationCast.cpp b/benchmarks/BM_interpolationCast.cpp deleted file mode 100644 index b3743530..00000000 --- a/benchmarks/BM_interpolationCast.cpp +++ /dev/null @@ -1,74 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause - -// This code is part of the sfizz library and is licensed under a BSD 2-clause -// license. You should have receive a LICENSE.md file along with the code. -// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz - -#include "SIMDHelpers.h" -#include -#include -#include -#include -#include - -// In this one we have an array of jumps - -constexpr float maxJump { 4 }; - -class InterpolationCast : public benchmark::Fixture { -public: - void SetUp(const ::benchmark::State& state) { - std::random_device rd { }; - std::mt19937 gen { rd() }; - std::uniform_real_distribution dist { 0, maxJump }; - jumps = std::vector(state.range(0)); - coeffs = std::vector(state.range(0)); - floatJumps = std::vector(state.range(0)); - absl::c_generate(floatJumps, [&]() { return dist(gen); }); - } - - void TearDown(const ::benchmark::State& /* state */) { - - } - - std::vector jumps; - std::vector coeffs; - std::vector floatJumps; -}; - - -BENCHMARK_DEFINE_F(InterpolationCast, Scalar)(benchmark::State& state) { - for (auto _ : state) - { - sfz::sfzInterpolationCast(floatJumps, absl::MakeSpan(jumps), absl::MakeSpan(coeffs)); - } -} - -BENCHMARK_DEFINE_F(InterpolationCast, SIMD)(benchmark::State& state) { - for (auto _ : state) - { - sfz::sfzInterpolationCast(floatJumps, absl::MakeSpan(jumps), absl::MakeSpan(coeffs)); - } -} - -BENCHMARK_DEFINE_F(InterpolationCast, Scalar_Unaligned)(benchmark::State& state) { - for (auto _ : state) - { - sfz::sfzInterpolationCast(absl::MakeSpan(floatJumps).subspan(1), absl::MakeSpan(jumps).subspan(3), absl::MakeSpan(coeffs).subspan(1)); - } -} - -BENCHMARK_DEFINE_F(InterpolationCast, SIMD_Unaligned)(benchmark::State& state) { - for (auto _ : state) - { - sfz::sfzInterpolationCast(absl::MakeSpan(floatJumps).subspan(1), absl::MakeSpan(jumps).subspan(3), absl::MakeSpan(coeffs).subspan(1)); - } -} - - -// Register the function as a benchmark -BENCHMARK_REGISTER_F(InterpolationCast, Scalar)->RangeMultiplier(2)->Range((2<<6), (2<<12)); -BENCHMARK_REGISTER_F(InterpolationCast, SIMD)->RangeMultiplier(2)->Range((2<<6), (2<<12)); -BENCHMARK_REGISTER_F(InterpolationCast, Scalar_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12)); -BENCHMARK_REGISTER_F(InterpolationCast, SIMD_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12)); -BENCHMARK_MAIN(); diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 0e44d964..ffae6f8c 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -54,7 +54,6 @@ sfizz_add_benchmark(bm_mean BM_mean.cpp) sfizz_add_benchmark(bm_meanSquared BM_meanSquared.cpp) sfizz_add_benchmark(bm_cumsum BM_cumsum.cpp) sfizz_add_benchmark(bm_diff BM_diff.cpp) -sfizz_add_benchmark(bm_interpolationCast BM_interpolationCast.cpp) sfizz_add_benchmark(bm_pointerIterationOrOffsets BM_pointerIterationOrOffsets.cpp) sfizz_add_benchmark(bm_maps BM_maps.cpp) target_link_libraries(bm_maps PRIVATE absl::flat_hash_map) diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index 1f2ab5e3..12accd63 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -616,6 +616,8 @@ void cumsum(absl::Span input, absl::Span output) noexcept template <> void cumsum(absl::Span input, absl::Span output) noexcept; +// FIXME: This should go away once the changes from the resampler are in + namespace _internals { template void snippetSFZInterpolationCast(const T*& floatJump, int*& jump, T*& coeff) @@ -631,13 +633,12 @@ namespace _internals { * and extracts the integer index of the elements to interpolate * * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version * @param floatJumps the floating point indices * @param jumps the integer indices outputs * @param leftCoeffs the left interpolation coefficients * @param rightCoeffs the right interpolation coefficients */ -template +template void sfzInterpolationCast(absl::Span floatJumps, absl::Span jumps, absl::Span coeffs) noexcept { CHECK(jumps.size() >= floatJumps.size()); @@ -652,9 +653,6 @@ void sfzInterpolationCast(absl::Span floatJumps, absl::Span jumps, _internals::snippetSFZInterpolationCast(floatJump, jump, coeff); } -template <> -void sfzInterpolationCast(absl::Span floatJumps, absl::Span jumps, absl::Span coeffs) noexcept; - namespace _internals { template inline void snippetDiff(const T*& input, T*& output) diff --git a/src/sfizz/SIMDSSE.cpp b/src/sfizz/SIMDSSE.cpp index f20938b7..9cf5ec04 100644 --- a/src/sfizz/SIMDSSE.cpp +++ b/src/sfizz/SIMDSSE.cpp @@ -116,36 +116,6 @@ void sfz::cumsum(absl::Span input, absl::Span o _internals::snippetCumsum(in, out); } -template <> -void sfz::sfzInterpolationCast(absl::Span floatJumps, absl::Span jumps, absl::Span coeffs) noexcept -{ - sfz::sfzInterpolationCast(floatJumps, jumps, coeffs); - // CHECK(jumps.size() >= floatJumps.size()); - // CHECK(jumps.size() == coeffs.size()); - - // auto floatJump = floatJumps.data(); - // auto jump = jumps.data(); - // auto coeff = coeffs.data(); - // const auto sentinel = floatJump + min(floatJumps.size(), jumps.size(), coeffs.size()); - // const auto lastAligned = prevAligned(sentinel); - - // while (unaligned(floatJump, reinterpret_cast(jump), coeff) && floatJump < lastAligned) - // _internals::snippetSFZInterpolationCast(floatJump, jump, coeff); - - // while (floatJump < lastAligned) { - // auto mmFloatJumps = _mm_load_ps(floatJump); - // auto mmIndices = _mm_cvtps_epi32(_mm_sub_ps(mmFloatJumps, _mm_set_ps1(0.4999999552965164184570312f))); - // _mm_store_si128(reinterpret_cast<__m128i*>(jump), mmIndices); - - // auto mmCoeff = _mm_sub_ps(mmFloatJumps, _mm_cvtepi32_ps(mmIndices)); - // _mm_store_ps(coeff, mmCoeff); - // incrementAll(floatJump, jump, coeff); - // } - - // while(floatJump < sentinel) - // _internals::snippetSFZInterpolationCast(floatJump, jump, coeff); -} - template <> void sfz::diff(absl::Span input, absl::Span output) noexcept { From 59f284a82bcdf6c0f71a957bad159c053b917060 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 31 May 2020 10:54:32 +0200 Subject: [PATCH 22/42] Move mean and meanSquared to the new format --- benchmarks/BM_mean.cpp | 12 +++-- benchmarks/BM_meanSquared.cpp | 12 +++-- src/sfizz/SIMDHelpers.cpp | 83 +++++++++++++++++++++++++++++++++++ src/sfizz/SIMDHelpers.h | 49 +++++++++++++-------- src/sfizz/SIMDSSE.cpp | 69 ----------------------------- tests/SIMDHelpersT.cpp | 24 +++++++--- 6 files changed, 148 insertions(+), 101 deletions(-) diff --git a/benchmarks/BM_mean.cpp b/benchmarks/BM_mean.cpp index 5ea0cc93..88d50624 100644 --- a/benchmarks/BM_mean.cpp +++ b/benchmarks/BM_mean.cpp @@ -34,7 +34,8 @@ BENCHMARK_DEFINE_F(MeanArray, Scalar) (benchmark::State& state) { for (auto _ : state) { - auto result = sfz::mean(input); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false); + auto result = sfz::mean(input); benchmark::DoNotOptimize(result); } } @@ -43,7 +44,8 @@ BENCHMARK_DEFINE_F(MeanArray, SIMD) (benchmark::State& state) { for (auto _ : state) { - auto result = sfz::mean(input); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true); + auto result = sfz::mean(input); benchmark::DoNotOptimize(result); } } @@ -52,7 +54,8 @@ BENCHMARK_DEFINE_F(MeanArray, Scalar_Unaligned) (benchmark::State& state) { for (auto _ : state) { - auto result = sfz::mean(absl::MakeSpan(input).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false); + auto result = sfz::mean(absl::MakeSpan(input).subspan(1)); benchmark::DoNotOptimize(result); } } @@ -61,7 +64,8 @@ BENCHMARK_DEFINE_F(MeanArray, SIMD_Unaligned) (benchmark::State& state) { for (auto _ : state) { - auto result = sfz::mean(absl::MakeSpan(input).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true); + auto result = sfz::mean(absl::MakeSpan(input).subspan(1)); benchmark::DoNotOptimize(result); } } diff --git a/benchmarks/BM_meanSquared.cpp b/benchmarks/BM_meanSquared.cpp index 41468cc0..ec8c1f5c 100644 --- a/benchmarks/BM_meanSquared.cpp +++ b/benchmarks/BM_meanSquared.cpp @@ -34,7 +34,8 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, Scalar) (benchmark::State& state) { for (auto _ : state) { - auto result = sfz::meanSquared(input); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); + auto result = sfz::meanSquared(input); benchmark::DoNotOptimize(result); } } @@ -43,7 +44,8 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, SIMD) (benchmark::State& state) { for (auto _ : state) { - auto result = sfz::meanSquared(input); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); + auto result = sfz::meanSquared(input); benchmark::DoNotOptimize(result); } } @@ -52,7 +54,8 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, Scalar_Unaligned) (benchmark::State& state) { for (auto _ : state) { - auto result = sfz::meanSquared(absl::MakeSpan(input).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); + auto result = sfz::meanSquared(absl::MakeSpan(input).subspan(1)); benchmark::DoNotOptimize(result); } } @@ -61,7 +64,8 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, SIMD_Unaligned) (benchmark::State& state) { for (auto _ : state) { - auto result = sfz::meanSquared(absl::MakeSpan(input).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); + auto result = sfz::meanSquared(absl::MakeSpan(input).subspan(1)); benchmark::DoNotOptimize(result); } } diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index d1c61bdc..24c9a882 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -471,4 +471,87 @@ void copy(const float* input, float* output, unsigned size) noexcept std::copy(input, sentinel, output); } +template <> +float mean(const float* vector, unsigned size) noexcept +{ + const auto sentinel = vector + size; + + float result { 0.0f }; + if (size == 0) + return result; + + if (getSIMDOpStatus(SIMDOps::mean)) { +#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 + if (cpuInfo.has_sse()) { + const auto* lastAligned = prevAligned(sentinel); + while (unaligned(vector) && vector < lastAligned) + result += *vector++; + + auto mmSums = _mm_setzero_ps(); + while (vector < lastAligned) { + mmSums = _mm_add_ps(mmSums, _mm_load_ps(vector)); + incrementAll<4>(vector); + } + + std::array sseResult; + _mm_store_ps(sseResult.data(), mmSums); + + for (auto sseValue : sseResult) + result += sseValue; + + // fallthrough from lastAligned to sentinel + } +#endif + } + + while (vector < sentinel) + result += *vector++; + + return result / static_cast(size); +} + +template <> +float meanSquared(const float* vector, unsigned size) noexcept +{ + const auto sentinel = vector + size; + + float result { 0.0f }; + if (size == 0) + return result; + + if (getSIMDOpStatus(SIMDOps::meanSquared)) { +#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 + if (cpuInfo.has_sse()) { + const auto* lastAligned = prevAligned(sentinel); + while (unaligned(vector) && vector < lastAligned){ + result += (*vector) * (*vector); + vector++; + } + + auto mmSums = _mm_setzero_ps(); + while (vector < lastAligned) { + const auto mmValues = _mm_load_ps(vector); + mmSums = _mm_add_ps(mmSums, _mm_mul_ps(mmValues, mmValues)); + incrementAll<4>(vector); + } + + std::array sseResult; + _mm_store_ps(sseResult.data(), mmSums); + + for (auto sseValue : sseResult) + result += sseValue; + + // fallthrough from lastAligned to sentinel + } +#endif + } + + while (vector < sentinel){ + result += (*vector) * (*vector); + vector++; + } + + return result / static_cast(size); +} + } diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index 12accd63..69d3bb42 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -525,30 +525,37 @@ void copy(absl::Span input, absl::Span output) noexcept copy(input.data(), output.data(), minSpanSize(input, output)); } + /** * @brief Computes the mean of a span * * @tparam T the underlying type - * @tparam SIMD use the SIMD version or the scalar version * @param vector + * @param size * @return T */ -template -T mean(absl::Span vector) noexcept +template +T mean(const T* vector, unsigned size) noexcept { T result{ 0.0 }; - if (vector.size() == 0) + if (size == 0) return result; - auto* value = vector.begin(); - while (value < vector.end()) - result += *value++; + const auto sentinel = vector + size; + while (vector < sentinel) + result += *vector++; - return result / static_cast(vector.size()); + return result / static_cast(size); } template <> -float mean(absl::Span vector) noexcept; +float mean(const float* vector, unsigned size) noexcept; + +template +T mean(absl::Span vector) noexcept +{ + return mean(vector.data(), vector.size()); +} /** * @brief Computes the mean squared of a span @@ -558,24 +565,30 @@ float mean(absl::Span vector) noexcept; * @param vector * @return T */ -template -T meanSquared(absl::Span vector) noexcept +template +T meanSquared(const T* vector, unsigned size) noexcept { T result{ 0.0 }; - if (vector.size() == 0) + if (size == 0) return result; - auto* value = vector.begin(); - while (value < vector.end()) { - result += (*value) * (*value); - value++; + const auto sentinel = vector + size; + while (vector < sentinel) { + result += (*vector) * (*vector); + vector++; } - return result / static_cast(vector.size()); + return result / static_cast(size); } template <> -float meanSquared(absl::Span vector) noexcept; +float meanSquared(const float* vector, unsigned size) noexcept; + +template +T meanSquared(absl::Span vector) noexcept +{ + return meanSquared(vector.data(), vector.size()); +} namespace _internals { template diff --git a/src/sfizz/SIMDSSE.cpp b/src/sfizz/SIMDSSE.cpp index 9cf5ec04..ca29d7ba 100644 --- a/src/sfizz/SIMDSSE.cpp +++ b/src/sfizz/SIMDSSE.cpp @@ -16,75 +16,6 @@ constexpr uintptr_t TypeAlignment = 4; -template <> -float sfz::mean(absl::Span vector) noexcept -{ - float result { 0.0 }; - if (vector.size() == 0) - return result; - - auto* value = vector.begin(); - auto* sentinel = vector.end(); - const auto* lastAligned = prevAligned(sentinel); - - while (unaligned(value) && value < lastAligned) - result += *value++; - - auto mmSums = _mm_setzero_ps(); - while (value < lastAligned) { - mmSums = _mm_add_ps(mmSums, _mm_load_ps(value)); - value += TypeAlignment; - } - - std::array sseResult; - _mm_store_ps(sseResult.data(), mmSums); - - for (auto sseValue : sseResult) - result += sseValue; - - while (value < sentinel) - result += *value++; - - return result / static_cast(vector.size()); -} - -template <> -float sfz::meanSquared(absl::Span vector) noexcept -{ - float result { 0.0 }; - if (vector.size() == 0) - return result; - - auto* value = vector.begin(); - auto* sentinel = vector.end(); - const auto* lastAligned = prevAligned(sentinel); - - while (unaligned(value) && value < lastAligned) { - result += (*value) * (*value); - value++; - } - - auto mmSums = _mm_setzero_ps(); - while (value < lastAligned) { - const auto mmValues = _mm_load_ps(value); - mmSums = _mm_add_ps(mmSums, _mm_mul_ps(mmValues, mmValues)); - value += TypeAlignment; - } - - std::array sseResult; - _mm_store_ps(sseResult.data(), mmSums); - - for (auto sseValue : sseResult) - result += sseValue; - - while (value < sentinel) { - result += (*value) * (*value); - value++; - } - - return result / static_cast(vector.size()); -} - template <> void sfz::cumsum(absl::Span input, absl::Span output) noexcept { diff --git a/tests/SIMDHelpersT.cpp b/tests/SIMDHelpersT.cpp index fd545249..0eefbd34 100644 --- a/tests/SIMDHelpersT.cpp +++ b/tests/SIMDHelpersT.cpp @@ -654,29 +654,41 @@ TEST_CASE("[Helpers] copy (SIMD vs scalar)") TEST_CASE("[Helpers] Mean") { std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f }; - REQUIRE(sfz::mean(input) == 5.5f); - REQUIRE(sfz::mean(input) == 5.5f); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false); + REQUIRE(sfz::mean(input) == 5.5f); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true); + REQUIRE(sfz::mean(input) == 5.5f); } TEST_CASE("[Helpers] Mean (SIMD vs scalar)") { std::vector input(bigBufferSize); absl::c_iota(input, 0.0f); - REQUIRE(sfz::mean(input) == Approx(sfz::mean(input)).margin(0.001)); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false); + auto scalarResult = sfz::mean(input); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true); + auto simdResult = sfz::mean(input); + REQUIRE( scalarResult == Approx(simdResult).margin(1e-3) ); } TEST_CASE("[Helpers] Mean Squared") { std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f }; - REQUIRE(sfz::meanSquared(input) == 38.5f); - REQUIRE(sfz::meanSquared(input) == 38.5f); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); + REQUIRE(sfz::meanSquared(input) == 38.5f); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); + REQUIRE(sfz::meanSquared(input) == 38.5f); } TEST_CASE("[Helpers] Mean Squared (SIMD vs scalar)") { std::vector input(medBufferSize); absl::c_iota(input, 0.0f); - REQUIRE(sfz::meanSquared(input) == sfz::meanSquared(input)); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); + auto scalarResult = sfz::meanSquared(input); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); + auto simdResult = sfz::meanSquared(input); + REQUIRE( scalarResult == Approx(simdResult).margin(1e-3) ); } TEST_CASE("[Helpers] Cumulative sum") From a83cd99040c8797f30c3eb89b839987c0fd28d8f Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 31 May 2020 12:40:18 +0200 Subject: [PATCH 23/42] Move cumsum to the new format --- benchmarks/BM_cumsum.cpp | 12 +++++++---- benchmarks/BM_diff.cpp | 2 +- benchmarks/BM_envelopes.cpp | 2 +- src/sfizz/SIMDHelpers.cpp | 42 ++++++++++++++++++++++++++++++++++++- src/sfizz/SIMDHelpers.h | 34 +++++++++++++++++------------- src/sfizz/SIMDSSE.cpp | 31 --------------------------- tests/SIMDHelpersT.cpp | 9 +++++--- 7 files changed, 77 insertions(+), 55 deletions(-) diff --git a/benchmarks/BM_cumsum.cpp b/benchmarks/BM_cumsum.cpp index c8626848..9df02b76 100644 --- a/benchmarks/BM_cumsum.cpp +++ b/benchmarks/BM_cumsum.cpp @@ -35,28 +35,32 @@ public: BENCHMARK_DEFINE_F(CumArray, Sum_Scalar)(benchmark::State& state) { for (auto _ : state) { - sfz::cumsum(input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, false); + sfz::cumsum(input, absl::MakeSpan(output)); } } BENCHMARK_DEFINE_F(CumArray, Sum_SIMD)(benchmark::State& state) { for (auto _ : state) { - sfz::cumsum(input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, true); + sfz::cumsum(input, absl::MakeSpan(output)); } } BENCHMARK_DEFINE_F(CumArray, Sum_Scalar_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::cumsum(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, false); + sfz::cumsum(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } BENCHMARK_DEFINE_F(CumArray, Sum_SIMD_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::cumsum(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, true); + sfz::cumsum(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } diff --git a/benchmarks/BM_diff.cpp b/benchmarks/BM_diff.cpp index af50441d..911556bb 100644 --- a/benchmarks/BM_diff.cpp +++ b/benchmarks/BM_diff.cpp @@ -22,7 +22,7 @@ public: input = std::vector(state.range(0)); output = std::vector(state.range(0)); std::generate(input.begin(), input.end(), [&]() { return dist(gen); }); - sfz::cumsum(input, absl::MakeSpan(input)); + sfz::cumsum(input, absl::MakeSpan(input)); } void TearDown(const ::benchmark::State& /* state */) { diff --git a/benchmarks/BM_envelopes.cpp b/benchmarks/BM_envelopes.cpp index 1fa3ae91..f58218a8 100644 --- a/benchmarks/BM_envelopes.cpp +++ b/benchmarks/BM_envelopes.cpp @@ -20,7 +20,7 @@ public: input = std::vector(state.range(0)); output = std::vector(state.range(0)); std::generate(input.begin(), input.end(), [&]() { return dist(gen); }); - sfz::cumsum(input, absl::MakeSpan(input)); + sfz::cumsum(input, absl::MakeSpan(input)); } void TearDown(const ::benchmark::State& /* state */) diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index 24c9a882..4dbff456 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -546,7 +546,7 @@ float meanSquared(const float* vector, unsigned size) noexcept #endif } - while (vector < sentinel){ + while (vector < sentinel) { result += (*vector) * (*vector); vector++; } @@ -554,4 +554,44 @@ float meanSquared(const float* vector, unsigned size) noexcept return result / static_cast(size); } +template <> +void cumsum(const float* input, float* output, unsigned size) noexcept +{ + if (size == 0) + return; + + const auto sentinel = output + size; + *output++ = *input++; + + if (getSIMDOpStatus(SIMDOps::cumsum)) { +#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 = *(output - 1) + *input++; + output++; + } + + auto mmOutput = _mm_set_ps1(*(output - 1)); + while (output < lastAligned) { + auto mmOffset = _mm_load_ps(input); + mmOffset = _mm_add_ps(mmOffset, _mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(mmOffset), 4))); + mmOffset = _mm_add_ps(mmOffset, _mm_shuffle_ps(_mm_setzero_ps(), mmOffset, _MM_SHUFFLE(1, 0, 0, 0))); + mmOutput = _mm_add_ps(mmOutput, mmOffset); + _mm_store_ps(output, mmOutput); + mmOutput = _mm_shuffle_ps(mmOutput, mmOutput, _MM_SHUFFLE(3, 3, 3, 3)); + incrementAll<4>(input, output); + } + // fallthrough from lastAligned to sentinel + } +#endif + } + + while (output < sentinel) { + *output = *(output - 1) + *input++; + output++; + } +} + } diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index 69d3bb42..509766f6 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -606,28 +606,34 @@ namespace _internals { * 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 cumsum(absl::Span input, absl::Span output) noexcept +template +void cumsum(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::snippetCumsum(in, out); + *output++ = *input++; + while (output < sentinel) { + *output = *(output - 1) + *input++; + output++; + } } template <> -void cumsum(absl::Span input, absl::Span output) noexcept; +void cumsum(const float* input, float* output, unsigned size) noexcept; + +template +void cumsum(absl::Span input, absl::Span output) noexcept +{ + CHECK_SPAN_SIZES(input, output); + cumsum(input.data(), output.data(), minSpanSize(input, output)); +} // FIXME: This should go away once the changes from the resampler are in diff --git a/src/sfizz/SIMDSSE.cpp b/src/sfizz/SIMDSSE.cpp index ca29d7ba..8e04801d 100644 --- a/src/sfizz/SIMDSSE.cpp +++ b/src/sfizz/SIMDSSE.cpp @@ -16,37 +16,6 @@ constexpr uintptr_t TypeAlignment = 4; -template <> -void sfz::cumsum(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::snippetCumsum(in, out); - - auto mmOutput = _mm_set_ps1(*(out - 1)); - while (in < lastAligned) { - auto mmOffset = _mm_load_ps(in); - mmOffset = _mm_add_ps(mmOffset, _mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(mmOffset), 4))); - mmOffset = _mm_add_ps(mmOffset, _mm_shuffle_ps(_mm_setzero_ps(), mmOffset, _MM_SHUFFLE(1, 0, 0, 0))); - mmOutput = _mm_add_ps(mmOutput, mmOffset); - _mm_store_ps(out, mmOutput); - mmOutput = _mm_shuffle_ps(mmOutput, mmOutput, _MM_SHUFFLE(3, 3, 3, 3)); - incrementAll(in, out); - } - - while (in < sentinel) - _internals::snippetCumsum(in, out); -} - template <> void sfz::diff(absl::Span input, absl::Span output) noexcept { diff --git a/tests/SIMDHelpersT.cpp b/tests/SIMDHelpersT.cpp index 0eefbd34..15003d9a 100644 --- a/tests/SIMDHelpersT.cpp +++ b/tests/SIMDHelpersT.cpp @@ -696,7 +696,8 @@ TEST_CASE("[Helpers] Cumulative sum") std::array input { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f }; // 1.1 2.3 3.6 5.0f 6.5 8.1 std::array output; std::array expected { 1.1f, 2.3f, 3.6f, 5.0f, 6.5f, 8.1f }; - sfz::cumsum(input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, false); + sfz::cumsum(input, absl::MakeSpan(output)); REQUIRE(approxEqual(output, expected)); } @@ -707,8 +708,10 @@ TEST_CASE("[Helpers] Cumulative sum (SIMD vs Scalar)") std::vector outputSIMD(bigBufferSize); sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); sfz::linearRamp(absl::MakeSpan(input), 0.0f, 0.1f); - sfz::cumsum(input, absl::MakeSpan(outputScalar)); - sfz::cumsum(input, absl::MakeSpan(outputSIMD)); + sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, false); + sfz::cumsum(input, absl::MakeSpan(outputScalar)); + sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, true); + sfz::cumsum(input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } From ba87df80091a7a52cc108b124b2fe582ed51340c Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 31 May 2020 12:48:52 +0200 Subject: [PATCH 24/42] 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)); } From ad1367a9607743fba595c6bd44d778f6ba58846d Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 31 May 2020 12:58:05 +0200 Subject: [PATCH 25/42] Remove the old simd files --- cmake/SfizzSIMDSourceFiles.cmake | 5 +- dpf.mk | 4 +- scripts/run_clang_tidy.sh | 2 +- src/sfizz/SIMDDummy.cpp | 177 ----------------------- src/sfizz/SIMDHelpers.cpp | 10 ++ src/sfizz/SIMDHelpers.h | 12 +- src/sfizz/SIMDNEON.cpp | 241 ------------------------------- src/sfizz/SIMDSSE.cpp | 19 --- 8 files changed, 15 insertions(+), 455 deletions(-) delete mode 100644 src/sfizz/SIMDDummy.cpp delete mode 100644 src/sfizz/SIMDNEON.cpp delete mode 100644 src/sfizz/SIMDSSE.cpp diff --git a/cmake/SfizzSIMDSourceFiles.cmake b/cmake/SfizzSIMDSourceFiles.cmake index 962d0fb0..edca20e6 100644 --- a/cmake/SfizzSIMDSourceFiles.cmake +++ b/cmake/SfizzSIMDSourceFiles.cmake @@ -2,10 +2,7 @@ macro(sfizz_add_simd_sources SOURCES_VAR PREFIX) # It needs a macro, otherwise the source properties cannot take effect. list (APPEND ${SOURCES_VAR} - ${PREFIX}/sfizz/SIMDSSE.cpp - ${PREFIX}/sfizz/SIMDHelpers.cpp - ${PREFIX}/sfizz/SIMDNEON.cpp - ${PREFIX}/sfizz/SIMDDummy.cpp) + ${PREFIX}/sfizz/SIMDHelpers.cpp) # For CPU-dispatched X86 sources # Always build them for all X86 targets. diff --git a/dpf.mk b/dpf.mk index a2734283..e9bfb051 100644 --- a/dpf.mk +++ b/dpf.mk @@ -96,9 +96,7 @@ SFIZZ_SOURCES = \ src/sfizz/sfizz_wrapper.cpp \ src/sfizz/SfzFilter.cpp \ src/sfizz/SfzHelpers.cpp \ - src/sfizz/SIMDDummy.cpp \ - src/sfizz/SIMDNEON.cpp \ - src/sfizz/SIMDSSE.cpp \ + src/sfizz/SIMDHelpers.cpp \ src/sfizz/Synth.cpp \ src/sfizz/Tuning.cpp \ src/sfizz/Voice.cpp \ diff --git a/scripts/run_clang_tidy.sh b/scripts/run_clang_tidy.sh index 6c1f6f8a..370171df 100755 --- a/scripts/run_clang_tidy.sh +++ b/scripts/run_clang_tidy.sh @@ -17,7 +17,7 @@ clang-tidy \ src/sfizz/sfizz.cpp \ src/sfizz/Region.cpp \ src/sfizz/SfzHelpers.cpp \ - src/sfizz/SIMDSSE.cpp \ + src/sfizz/SIMDHelpers.cpp \ src/sfizz/Synth.cpp \ src/sfizz/Voice.cpp \ src/sfizz/effects/Eq.cpp \ diff --git a/src/sfizz/SIMDDummy.cpp b/src/sfizz/SIMDDummy.cpp deleted file mode 100644 index 718d8a1c..00000000 --- a/src/sfizz/SIMDDummy.cpp +++ /dev/null @@ -1,177 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause - -// This code is part of the sfizz library and is licensed under a BSD 2-clause -// license. You should have receive a LICENSE.md file along with the code. -// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz - -#include "SIMDConfig.h" - -#if !(SFIZZ_HAVE_SSE2 || SFIZZ_HAVE_NEON) - -#include "SIMDHelpers.h" - -template <> -void sfz::readInterleaved(absl::Span input, absl::Span outputLeft, absl::Span outputRight) noexcept -{ - readInterleaved(input, outputLeft, outputRight); -} - -template <> -void sfz::writeInterleaved(absl::Span inputLeft, absl::Span inputRight, absl::Span output) noexcept -{ - writeInterleaved(inputLeft, inputRight, output); -} - -template <> -void sfz::fill(absl::Span output, float value) noexcept -{ - fill(output, value); -} - -template <> -void sfz::exp(absl::Span input, absl::Span output) noexcept -{ - exp(input, output); -} - -template <> -void sfz::log(absl::Span input, absl::Span output) noexcept -{ - log(input, output); -} - -template <> -void sfz::sin(absl::Span input, absl::Span output) noexcept -{ - sin(input, output); -} - -template <> -void sfz::cos(absl::Span input, absl::Span output) noexcept -{ - cos(input, output); -} - -template <> -void sfz::applyGain(float gain, absl::Span input, absl::Span output) noexcept -{ - applyGain(gain, input, output); -} - -template <> -void sfz::applyGain(absl::Span gain, absl::Span input, absl::Span output) noexcept -{ - applyGain(gain, input, output); -} - -template <> -void sfz::divide(absl::Span input, absl::Span divisor, absl::Span output) noexcept -{ - divide(input, divisor, output); -} - -template <> -void sfz::multiplyAdd(absl::Span gain, absl::Span input, absl::Span output) noexcept -{ - multiplyAdd(gain, input, output); -} - -template <> -void sfz::multiplyAdd(const float gain, absl::Span input, absl::Span output) noexcept -{ - multiplyAdd(gain, input, output); -} - -template <> -float sfz::loopingSFZIndex(absl::Span jumps, absl::Span leftCoeff, absl::Span rightCoeff, absl::Span indices, float floatIndex, float loopEnd, float loopStart) noexcept -{ - return loopingSFZIndex(jumps, leftCoeff, rightCoeff, indices, floatIndex, loopEnd, loopStart); -} - -template <> -float sfz::saturatingSFZIndex(absl::Span jumps, absl::Span leftCoeff, absl::Span rightCoeff, absl::Span indices, float floatIndex, float loopEnd) noexcept -{ - return saturatingSFZIndex(jumps, leftCoeff, rightCoeff, indices, floatIndex, loopEnd); -} - - -template <> -float sfz::linearRamp(absl::Span output, float start, float step) noexcept -{ - return linearRamp(output, start, step); -} - -template <> -float sfz::multiplicativeRamp(absl::Span output, float start, float step) noexcept -{ - return multiplicativeRamp(output, start, step); -} - -template <> -void sfz::add(absl::Span input, absl::Span output) noexcept -{ - add(input, output); -} - -template <> -void sfz::add(float value, absl::Span output) noexcept -{ - add(value, output); -} - -template <> -void sfz::subtract(absl::Span input, absl::Span output) noexcept -{ - subtract(input, output); -} - -template <> -void sfz::subtract(const float value, absl::Span output) noexcept -{ - subtract(value, output); -} - - -template <> -void sfz::copy(absl::Span input, absl::Span output) noexcept -{ - copy(input, output); -} - -template <> -void sfz::pan(absl::Span panEnvelope, absl::Span leftBuffer, absl::Span rightBuffer) noexcept -{ - pan(panEnvelope, leftBuffer, rightBuffer); -} - -template <> -float sfz::mean(absl::Span vector) noexcept -{ - return mean(vector); -} - -template <> -float sfz::meanSquared(absl::Span vector) noexcept -{ - return meanSquared(vector); -} - -template <> -void sfz::cumsum(absl::Span input, absl::Span output) noexcept -{ - cumsum(input, output); -} - -template<> -void sfz::sfzInterpolationCast(absl::Span floatJumps, absl::Span jumps, absl::Span coeffs) noexcept -{ - sfzInterpolationCast(floatJumps, jumps, coeffs); -} - -template <> -void sfz::diff(absl::Span input, absl::Span output) noexcept -{ - diff(input, output); -} - -#endif // !(SFIZZ_HAVE_SSE2 || SFIZZ_HAVE_NEON) diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index da87bc8e..5fd4d226 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -9,6 +9,10 @@ #include #endif +#if SFIZZ_HAVE_NEON +#include +#endif + namespace sfz { static std::array(SIMDOps::_sentinel)> simdStatus; @@ -100,6 +104,12 @@ void readInterleaved(const float* input, float* outputLeft, float* outputRight, // Fallthrough from lastAligned to sentinel } #endif + +#if 0 // NEON wip + auto reg = vld2q_f32(in); + vst1q_f32(lOut, reg.val[0]); + vst1q_f32(rOut, reg.val[1]); +#endif } while (input < sentinel) diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index 5d3fea02..acc2c526 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -12,16 +12,8 @@ * These functions are templated to apply on * various underlying buffer types, and this file contains the generic version of the * function. Some templates specializations exists for different architecture that try - * to make use of SIMD intrinsics; you can find such a file in SIMDSSE.cpp and possibly - * someday SIMDNEON.cpp for ARM platforms. - * - * If you want to write specializations for float buffers the idea is to start from the SIMDDummy - * file that just calls back the generic implementation, and implement the specializations you - * wish from this list. You can then either activate or deactivate a SIMD version by default - * using the variables in Config.h, or call e.g. writeInterleaved(...) to use the - * SIMD version of writeInterleaved. To implement e.g. double template specializations you - * will need to amend this file to pre-declare the specializations, and create a file similar to - * SIMDxxx.cpp. + * to make use of SIMD intrinsics in SIMDHelpers.cpp. A runtime dispatch can help if you + * write implementation for larger/newer SIMD operations. * * All the SIMD functions are benchmarked. If you run the benchmark for a given function you can check * if it is interesting to run the SIMD version by default. The interest is that you can activate diff --git a/src/sfizz/SIMDNEON.cpp b/src/sfizz/SIMDNEON.cpp deleted file mode 100644 index e229d954..00000000 --- a/src/sfizz/SIMDNEON.cpp +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright (c) 2019, Paul Ferrand -// All rights reserved. - -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: - -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. - -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "SIMDConfig.h" - -#if SFIZZ_HAVE_NEON - -#include "SIMDHelpers.h" -#include - -using Type = float; -constexpr uintptr_t TypeAlignment { 4 }; -constexpr uintptr_t ByteAlignment { TypeAlignment * sizeof(Type) }; -constexpr uintptr_t ByteAlignmentMask { ByteAlignment - 1 }; - -float* nextAligned(const float* ptr) -{ - return reinterpret_cast((reinterpret_cast(ptr) + ByteAlignmentMask) & (~ByteAlignmentMask)); -} - -float* prevAligned(const float* ptr) -{ - return reinterpret_cast(reinterpret_cast(ptr) & (~ByteAlignmentMask)); -} - -bool unaligned(const float* ptr) -{ - return (reinterpret_cast(ptr) & ByteAlignmentMask) != 0; -} - -template -bool unaligned(const float* ptr1, Args... rest) -{ - return unaligned(ptr1) || unaligned(rest...); -} - -template <> -void sfz::readInterleaved(absl::Span input, absl::Span outputLeft, absl::Span outputRight) noexcept -{ - // The size of the outputs is not big enough for the input... - ASSERT(outputLeft.size() >= input.size() / 2); - ASSERT(outputRight.size() >= input.size() / 2); - // Input is too small - ASSERT(input.size() > 1); - - auto* in = input.begin(); - auto* lOut = outputLeft.begin(); - auto* rOut = outputRight.begin(); - - const auto size = std::min(input.size(), std::min(outputLeft.size() * 2, outputRight.size() * 2)); - const auto* lastAligned = prevAligned(input.begin() + size - TypeAlignment); - - while (unaligned(in, lOut, rOut) && in < lastAligned) - _internals::snippetRead(in, lOut, rOut); - - while (in < lastAligned) { - auto reg = vld2q_f32(in); - vst1q_f32(lOut, reg.val[0]); - vst1q_f32(rOut, reg.val[1]); - // *lOut = reg.val[0]; - // *rOut = reg.val[1]; - incrementAll(in, in, lOut, rOut); - } - - while (in < input.end() - 1) - _internals::snippetRead(in, lOut, rOut); -} - -template <> -void sfz::writeInterleaved(absl::Span inputLeft, absl::Span inputRight, absl::Span output) noexcept -{ - writeInterleaved(inputLeft, inputRight, output); -} - -template <> -void sfz::fill(absl::Span output, float value) noexcept -{ - fill(output, value); -} - -template <> -void sfz::exp(absl::Span input, absl::Span output) noexcept -{ - exp(input, output); -} - -template <> -void sfz::log(absl::Span input, absl::Span output) noexcept -{ - log(input, output); -} - -template <> -void sfz::sin(absl::Span input, absl::Span output) noexcept -{ - sin(input, output); -} - -template <> -void sfz::cos(absl::Span input, absl::Span output) noexcept -{ - cos(input, output); -} - -template <> -void sfz::applyGain(float gain, absl::Span input, absl::Span output) noexcept -{ - applyGain(gain, input, output); -} - -template <> -void sfz::applyGain(absl::Span gain, absl::Span input, absl::Span output) noexcept -{ - applyGain(gain, input, output); -} - -template <> -void sfz::divide(absl::Span input, absl::Span divisor, absl::Span output) noexcept -{ - divide(input, divisor, output); -} - -template <> -void sfz::multiplyAdd(absl::Span gain, absl::Span input, absl::Span output) noexcept -{ - multiplyAdd(gain, input, output); -} - -template <> -float sfz::loopingSFZIndex(absl::Span jumps, absl::Span leftCoeff, absl::Span rightCoeff, absl::Span indices, float floatIndex, float loopEnd, float loopStart) noexcept -{ - return loopingSFZIndex(jumps, leftCoeff, rightCoeff, indices, floatIndex, loopEnd, loopStart); -} - -template <> -float sfz::saturatingSFZIndex(absl::Span jumps, absl::Span leftCoeff, absl::Span rightCoeff, absl::Span indices, float floatIndex, float loopEnd) noexcept -{ - return saturatingSFZIndex(jumps, leftCoeff, rightCoeff, indices, floatIndex, loopEnd); -} - - -template <> -float sfz::linearRamp(absl::Span output, float start, float step) noexcept -{ - return linearRamp(output, start, step); -} - -template <> -float sfz::multiplicativeRamp(absl::Span output, float start, float step) noexcept -{ - return multiplicativeRamp(output, start, step); -} - -template <> -void sfz::add(absl::Span input, absl::Span output) noexcept -{ - add(input, output); -} - -template <> -void sfz::add(float value, absl::Span output) noexcept -{ - add(value, output); -} - -template <> -void sfz::subtract(absl::Span input, absl::Span output) noexcept -{ - subtract(input, output); -} - -template <> -void sfz::subtract(const float value, absl::Span output) noexcept -{ - subtract(value, output); -} - - -template <> -void sfz::copy(absl::Span input, absl::Span output) noexcept -{ - copy(input, output); -} - -template <> -void sfz::pan(absl::Span panEnvelope, absl::Span leftBuffer, absl::Span rightBuffer) noexcept -{ - pan(panEnvelope, leftBuffer, rightBuffer); -} - -template <> -float sfz::mean(absl::Span vector) noexcept -{ - return mean(vector); -} - -template <> -float sfz::meanSquared(absl::Span vector) noexcept -{ - return meanSquared(vector); -} - -template <> -void sfz::cumsum(absl::Span input, absl::Span output) noexcept -{ - cumsum(input, output); -} - -template<> -void sfz::sfzInterpolationCast(absl::Span floatJumps, absl::Span jumps, absl::Span coeffs) noexcept -{ - sfzInterpolationCast(floatJumps, jumps, coeffs); -} - -template <> -void sfz::diff(absl::Span input, absl::Span output) noexcept -{ - diff(input, output); -} - -#endif // SFIZZ_HAVE_NEON diff --git a/src/sfizz/SIMDSSE.cpp b/src/sfizz/SIMDSSE.cpp deleted file mode 100644 index d3c023db..00000000 --- a/src/sfizz/SIMDSSE.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause - -// This code is part of the sfizz library and is licensed under a BSD 2-clause -// license. You should have receive a LICENSE.md file along with the code. -// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz - -#include "SIMDConfig.h" - -#if SFIZZ_HAVE_SSE2 - -#include "SIMDHelpers.h" -#include -#include -#include -#include "mathfuns/sse_mathfun.h" - -constexpr uintptr_t TypeAlignment = 4; - -#endif // SFIZZ_HAVE_SSE2 From 145c243c32a8f58f1bf9ebf15e214c7fe6bbb530 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 31 May 2020 12:59:52 +0200 Subject: [PATCH 26/42] Removed mathfuns (now unused) --- README.md | 2 - src/external/mathfuns/neon_mathfun.h | 301 ----------- src/external/mathfuns/sse_mathfun.h | 713 --------------------------- 3 files changed, 1016 deletions(-) delete mode 100644 src/external/mathfuns/neon_mathfun.h delete mode 100644 src/external/mathfuns/sse_mathfun.h diff --git a/README.md b/README.md index 60ab196c..4ee9292a 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,6 @@ The sfizz library also uses in some subprojects: - [benchmark], licensed under the Apache License 2.0 - [LV2], licensed under the ISC license - [JACK], licensed under the GNU Lesser General Public License v2.1 -- `neon_mathfun.h` and `sse_mathfun.h` by Julien Pommier, - licensed under the zlib license [Abseil]: https://github.com/abseil/abseil-cpp [atomic_queue]: https://github.com/max0x7ba/atomic_queue diff --git a/src/external/mathfuns/neon_mathfun.h b/src/external/mathfuns/neon_mathfun.h deleted file mode 100644 index f51a61e1..00000000 --- a/src/external/mathfuns/neon_mathfun.h +++ /dev/null @@ -1,301 +0,0 @@ -/* NEON implementation of sin, cos, exp and log - - Inspired by Intel Approximate Math library, and based on the - corresponding algorithms of the cephes math library -*/ - -/* Copyright (C) 2011 Julien Pommier - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - (this is the zlib license) -*/ - -#include - -typedef float32x4_t v4sf; // vector of 4 float -typedef uint32x4_t v4su; // vector of 4 uint32 -typedef int32x4_t v4si; // vector of 4 uint32 - -#define c_inv_mant_mask ~0x7f800000u -#define c_cephes_SQRTHF 0.707106781186547524 -#define c_cephes_log_p0 7.0376836292E-2 -#define c_cephes_log_p1 - 1.1514610310E-1 -#define c_cephes_log_p2 1.1676998740E-1 -#define c_cephes_log_p3 - 1.2420140846E-1 -#define c_cephes_log_p4 + 1.4249322787E-1 -#define c_cephes_log_p5 - 1.6668057665E-1 -#define c_cephes_log_p6 + 2.0000714765E-1 -#define c_cephes_log_p7 - 2.4999993993E-1 -#define c_cephes_log_p8 + 3.3333331174E-1 -#define c_cephes_log_q1 -2.12194440e-4 -#define c_cephes_log_q2 0.693359375 - -/* natural logarithm computed for 4 simultaneous float - return NaN for x <= 0 -*/ -v4sf log_ps(v4sf x) { - v4sf one = vdupq_n_f32(1); - - x = vmaxq_f32(x, vdupq_n_f32(0)); /* force flush to zero on denormal values */ - v4su invalid_mask = vcleq_f32(x, vdupq_n_f32(0)); - - v4si ux = vreinterpretq_s32_f32(x); - - v4si emm0 = vshrq_n_s32(ux, 23); - - /* keep only the fractional part */ - ux = vandq_s32(ux, vdupq_n_s32(c_inv_mant_mask)); - ux = vorrq_s32(ux, vreinterpretq_s32_f32(vdupq_n_f32(0.5f))); - x = vreinterpretq_f32_s32(ux); - - emm0 = vsubq_s32(emm0, vdupq_n_s32(0x7f)); - v4sf e = vcvtq_f32_s32(emm0); - - e = vaddq_f32(e, one); - - /* part2: - if( x < SQRTHF ) { - e -= 1; - x = x + x - 1.0; - } else { x = x - 1.0; } - */ - v4su mask = vcltq_f32(x, vdupq_n_f32(c_cephes_SQRTHF)); - v4sf tmp = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(x), mask)); - x = vsubq_f32(x, one); - e = vsubq_f32(e, vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(one), mask))); - x = vaddq_f32(x, tmp); - - v4sf z = vmulq_f32(x,x); - - v4sf y = vdupq_n_f32(c_cephes_log_p0); - y = vmulq_f32(y, x); - y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p1)); - y = vmulq_f32(y, x); - y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p2)); - y = vmulq_f32(y, x); - y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p3)); - y = vmulq_f32(y, x); - y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p4)); - y = vmulq_f32(y, x); - y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p5)); - y = vmulq_f32(y, x); - y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p6)); - y = vmulq_f32(y, x); - y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p7)); - y = vmulq_f32(y, x); - y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p8)); - y = vmulq_f32(y, x); - - y = vmulq_f32(y, z); - - - tmp = vmulq_f32(e, vdupq_n_f32(c_cephes_log_q1)); - y = vaddq_f32(y, tmp); - - - tmp = vmulq_f32(z, vdupq_n_f32(0.5f)); - y = vsubq_f32(y, tmp); - - tmp = vmulq_f32(e, vdupq_n_f32(c_cephes_log_q2)); - x = vaddq_f32(x, y); - x = vaddq_f32(x, tmp); - x = vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(x), invalid_mask)); // negative arg will be NAN - return x; -} - -#define c_exp_hi 88.3762626647949f -#define c_exp_lo -88.3762626647949f - -#define c_cephes_LOG2EF 1.44269504088896341 -#define c_cephes_exp_C1 0.693359375 -#define c_cephes_exp_C2 -2.12194440e-4 - -#define c_cephes_exp_p0 1.9875691500E-4 -#define c_cephes_exp_p1 1.3981999507E-3 -#define c_cephes_exp_p2 8.3334519073E-3 -#define c_cephes_exp_p3 4.1665795894E-2 -#define c_cephes_exp_p4 1.6666665459E-1 -#define c_cephes_exp_p5 5.0000001201E-1 - -/* exp() computed for 4 float at once */ -v4sf exp_ps(v4sf x) { - v4sf tmp, fx; - - v4sf one = vdupq_n_f32(1); - x = vminq_f32(x, vdupq_n_f32(c_exp_hi)); - x = vmaxq_f32(x, vdupq_n_f32(c_exp_lo)); - - /* express exp(x) as exp(g + n*log(2)) */ - fx = vmlaq_f32(vdupq_n_f32(0.5f), x, vdupq_n_f32(c_cephes_LOG2EF)); - - /* perform a floorf */ - tmp = vcvtq_f32_s32(vcvtq_s32_f32(fx)); - - /* if greater, substract 1 */ - v4su mask = vcgtq_f32(tmp, fx); - mask = vandq_u32(mask, vreinterpretq_u32_f32(one)); - - - fx = vsubq_f32(tmp, vreinterpretq_f32_u32(mask)); - - tmp = vmulq_f32(fx, vdupq_n_f32(c_cephes_exp_C1)); - v4sf z = vmulq_f32(fx, vdupq_n_f32(c_cephes_exp_C2)); - x = vsubq_f32(x, tmp); - x = vsubq_f32(x, z); - - static const float cephes_exp_p[6] = { c_cephes_exp_p0, c_cephes_exp_p1, c_cephes_exp_p2, c_cephes_exp_p3, c_cephes_exp_p4, c_cephes_exp_p5 }; - v4sf y = vld1q_dup_f32(cephes_exp_p+0); - v4sf c1 = vld1q_dup_f32(cephes_exp_p+1); - v4sf c2 = vld1q_dup_f32(cephes_exp_p+2); - v4sf c3 = vld1q_dup_f32(cephes_exp_p+3); - v4sf c4 = vld1q_dup_f32(cephes_exp_p+4); - v4sf c5 = vld1q_dup_f32(cephes_exp_p+5); - - y = vmulq_f32(y, x); - z = vmulq_f32(x,x); - y = vaddq_f32(y, c1); - y = vmulq_f32(y, x); - y = vaddq_f32(y, c2); - y = vmulq_f32(y, x); - y = vaddq_f32(y, c3); - y = vmulq_f32(y, x); - y = vaddq_f32(y, c4); - y = vmulq_f32(y, x); - y = vaddq_f32(y, c5); - - y = vmulq_f32(y, z); - y = vaddq_f32(y, x); - y = vaddq_f32(y, one); - - /* build 2^n */ - int32x4_t mm; - mm = vcvtq_s32_f32(fx); - mm = vaddq_s32(mm, vdupq_n_s32(0x7f)); - mm = vshlq_n_s32(mm, 23); - v4sf pow2n = vreinterpretq_f32_s32(mm); - - y = vmulq_f32(y, pow2n); - return y; -} - -#define c_minus_cephes_DP1 -0.78515625 -#define c_minus_cephes_DP2 -2.4187564849853515625e-4 -#define c_minus_cephes_DP3 -3.77489497744594108e-8 -#define c_sincof_p0 -1.9515295891E-4 -#define c_sincof_p1 8.3321608736E-3 -#define c_sincof_p2 -1.6666654611E-1 -#define c_coscof_p0 2.443315711809948E-005 -#define c_coscof_p1 -1.388731625493765E-003 -#define c_coscof_p2 4.166664568298827E-002 -#define c_cephes_FOPI 1.27323954473516 // 4 / M_PI - -/* evaluation of 4 sines & cosines at once. - - The code is the exact rewriting of the cephes sinf function. - Precision is excellent as long as x < 8192 (I did not bother to - take into account the special handling they have for greater values - -- it does not return garbage for arguments over 8192, though, but - the extra precision is missing). - - Note that it is such that sinf((float)M_PI) = 8.74e-8, which is the - surprising but correct result. - - Note also that when you compute sin(x), cos(x) is available at - almost no extra price so both sin_ps and cos_ps make use of - sincos_ps.. - */ -void sincos_ps(v4sf x, v4sf *ysin, v4sf *ycos) { // any x - v4sf xmm1, xmm2, xmm3, y; - - v4su emm2; - - v4su sign_mask_sin, sign_mask_cos; - sign_mask_sin = vcltq_f32(x, vdupq_n_f32(0)); - x = vabsq_f32(x); - - /* scale by 4/Pi */ - y = vmulq_f32(x, vdupq_n_f32(c_cephes_FOPI)); - - /* store the integer part of y in mm0 */ - emm2 = vcvtq_u32_f32(y); - /* j=(j+1) & (~1) (see the cephes sources) */ - emm2 = vaddq_u32(emm2, vdupq_n_u32(1)); - emm2 = vandq_u32(emm2, vdupq_n_u32(~1)); - y = vcvtq_f32_u32(emm2); - - /* get the polynom selection mask - there is one polynom for 0 <= x <= Pi/4 - and another one for Pi/4 - -/* yes I know, the top of this file is quite ugly */ - -#ifdef _MSC_VER /* visual c++ */ -# define ALIGN16_BEG __declspec(align(16)) -# define ALIGN16_END -#else /* gcc or icc */ -# define ALIGN16_BEG -# define ALIGN16_END __attribute__((aligned(16))) -#endif - -#define USE_SSE2 - -/* __m128 is ugly to write */ -typedef __m128 v4sf; // vector of 4 float (sse1) - -#ifdef USE_SSE2 -# include -typedef __m128i v4si; // vector of 4 int (sse2) -#else -typedef __m64 v2si; // vector of 2 int (mmx) -#endif - -/* declare some SSE constants -- why can't I figure a better way to do that? */ -#define _PS_CONST(Name, Val) \ - static const ALIGN16_BEG float _ps_##Name[4] ALIGN16_END = { Val, Val, Val, Val } -#define _PI32_CONST(Name, Val) \ - static const ALIGN16_BEG int _pi32_##Name[4] ALIGN16_END = { Val, Val, Val, Val } -#define _PS_CONST_TYPE(Name, Type, Val) \ - static const ALIGN16_BEG Type _ps_##Name[4] ALIGN16_END = { Val, Val, Val, Val } - -_PS_CONST(1 , 1.0f); -_PS_CONST(0p5, 0.5f); -/* the smallest non denormalized float number */ -_PS_CONST_TYPE(min_norm_pos, int, 0x00800000); -_PS_CONST_TYPE(mant_mask, int, 0x7f800000); -_PS_CONST_TYPE(inv_mant_mask, int, ~0x7f800000); - -_PS_CONST_TYPE(sign_mask, int, (int)0x80000000); -_PS_CONST_TYPE(inv_sign_mask, int, ~0x80000000); - -_PI32_CONST(1, 1); -_PI32_CONST(inv1, ~1); -_PI32_CONST(2, 2); -_PI32_CONST(4, 4); -_PI32_CONST(0x7f, 0x7f); - -_PS_CONST(cephes_SQRTHF, 0.707106781186547524f); -_PS_CONST(cephes_log_p0, 7.0376836292E-2f); -_PS_CONST(cephes_log_p1, - 1.1514610310E-1f); -_PS_CONST(cephes_log_p2, 1.1676998740E-1f); -_PS_CONST(cephes_log_p3, - 1.2420140846E-1f); -_PS_CONST(cephes_log_p4, + 1.4249322787E-1f); -_PS_CONST(cephes_log_p5, - 1.6668057665E-1f); -_PS_CONST(cephes_log_p6, + 2.0000714765E-1f); -_PS_CONST(cephes_log_p7, - 2.4999993993E-1f); -_PS_CONST(cephes_log_p8, + 3.3333331174E-1f); -_PS_CONST(cephes_log_q1, -2.12194440e-4f); -_PS_CONST(cephes_log_q2, 0.693359375f); - -#ifndef USE_SSE2 -typedef union xmm_mm_union { - __m128 xmm; - __m64 mm[2]; -} xmm_mm_union; - -#define COPY_XMM_TO_MM(xmm_, mm0_, mm1_) { \ - xmm_mm_union u; u.xmm = xmm_; \ - mm0_ = u.mm[0]; \ - mm1_ = u.mm[1]; \ -} - -#define COPY_MM_TO_XMM(mm0_, mm1_, xmm_) { \ - xmm_mm_union u; u.mm[0]=mm0_; u.mm[1]=mm1_; xmm_ = u.xmm; \ - } - -#endif // USE_SSE2 - -/* natural logarithm computed for 4 simultaneous float - return NaN for x <= 0 -*/ -v4sf log_ps(v4sf x) { -#ifdef USE_SSE2 - v4si emm0; -#else - v2si mm0, mm1; -#endif - v4sf one = *(v4sf*)_ps_1; - - v4sf invalid_mask = _mm_cmple_ps(x, _mm_setzero_ps()); - - x = _mm_max_ps(x, *(v4sf*)_ps_min_norm_pos); /* cut off denormalized stuff */ - -#ifndef USE_SSE2 - /* part 1: x = frexpf(x, &e); */ - COPY_XMM_TO_MM(x, mm0, mm1); - mm0 = _mm_srli_pi32(mm0, 23); - mm1 = _mm_srli_pi32(mm1, 23); -#else - emm0 = _mm_srli_epi32(_mm_castps_si128(x), 23); -#endif - /* keep only the fractional part */ - x = _mm_and_ps(x, *(v4sf*)_ps_inv_mant_mask); - x = _mm_or_ps(x, *(v4sf*)_ps_0p5); - -#ifndef USE_SSE2 - /* now e=mm0:mm1 contain the really base-2 exponent */ - mm0 = _mm_sub_pi32(mm0, *(v2si*)_pi32_0x7f); - mm1 = _mm_sub_pi32(mm1, *(v2si*)_pi32_0x7f); - v4sf e = _mm_cvtpi32x2_ps(mm0, mm1); - _mm_empty(); /* bye bye mmx */ -#else - emm0 = _mm_sub_epi32(emm0, *(v4si*)_pi32_0x7f); - v4sf e = _mm_cvtepi32_ps(emm0); -#endif - - e = _mm_add_ps(e, one); - - /* part2: - if( x < SQRTHF ) { - e -= 1; - x = x + x - 1.0; - } else { x = x - 1.0; } - */ - v4sf mask = _mm_cmplt_ps(x, *(v4sf*)_ps_cephes_SQRTHF); - v4sf tmp = _mm_and_ps(x, mask); - x = _mm_sub_ps(x, one); - e = _mm_sub_ps(e, _mm_and_ps(one, mask)); - x = _mm_add_ps(x, tmp); - - - v4sf z = _mm_mul_ps(x,x); - - v4sf y = *(v4sf*)_ps_cephes_log_p0; - y = _mm_mul_ps(y, x); - y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p1); - y = _mm_mul_ps(y, x); - y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p2); - y = _mm_mul_ps(y, x); - y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p3); - y = _mm_mul_ps(y, x); - y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p4); - y = _mm_mul_ps(y, x); - y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p5); - y = _mm_mul_ps(y, x); - y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p6); - y = _mm_mul_ps(y, x); - y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p7); - y = _mm_mul_ps(y, x); - y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p8); - y = _mm_mul_ps(y, x); - - y = _mm_mul_ps(y, z); - - - tmp = _mm_mul_ps(e, *(v4sf*)_ps_cephes_log_q1); - y = _mm_add_ps(y, tmp); - - - tmp = _mm_mul_ps(z, *(v4sf*)_ps_0p5); - y = _mm_sub_ps(y, tmp); - - tmp = _mm_mul_ps(e, *(v4sf*)_ps_cephes_log_q2); - x = _mm_add_ps(x, y); - x = _mm_add_ps(x, tmp); - x = _mm_or_ps(x, invalid_mask); // negative arg will be NAN - return x; -} - -_PS_CONST(exp_hi, 88.3762626647949f); -_PS_CONST(exp_lo, -88.3762626647949f); - -_PS_CONST(cephes_LOG2EF, 1.44269504088896341f); -_PS_CONST(cephes_exp_C1, 0.693359375f); -_PS_CONST(cephes_exp_C2, -2.12194440e-4f); - -_PS_CONST(cephes_exp_p0, 1.9875691500E-4f); -_PS_CONST(cephes_exp_p1, 1.3981999507E-3f); -_PS_CONST(cephes_exp_p2, 8.3334519073E-3f); -_PS_CONST(cephes_exp_p3, 4.1665795894E-2f); -_PS_CONST(cephes_exp_p4, 1.6666665459E-1f); -_PS_CONST(cephes_exp_p5, 5.0000001201E-1f); - -v4sf exp_ps(v4sf x) { - v4sf tmp = _mm_setzero_ps(), fx; -#ifdef USE_SSE2 - v4si emm0; -#else - v2si mm0, mm1; -#endif - v4sf one = *(v4sf*)_ps_1; - - x = _mm_min_ps(x, *(v4sf*)_ps_exp_hi); - x = _mm_max_ps(x, *(v4sf*)_ps_exp_lo); - - /* express exp(x) as exp(g + n*log(2)) */ - fx = _mm_mul_ps(x, *(v4sf*)_ps_cephes_LOG2EF); - fx = _mm_add_ps(fx, *(v4sf*)_ps_0p5); - - /* how to perform a floorf with SSE: just below */ -#ifndef USE_SSE2 - /* step 1 : cast to int */ - tmp = _mm_movehl_ps(tmp, fx); - mm0 = _mm_cvttps_pi32(fx); - mm1 = _mm_cvttps_pi32(tmp); - /* step 2 : cast back to float */ - tmp = _mm_cvtpi32x2_ps(mm0, mm1); -#else - emm0 = _mm_cvttps_epi32(fx); - tmp = _mm_cvtepi32_ps(emm0); -#endif - /* if greater, substract 1 */ - v4sf mask = _mm_cmpgt_ps(tmp, fx); - mask = _mm_and_ps(mask, one); - fx = _mm_sub_ps(tmp, mask); - - tmp = _mm_mul_ps(fx, *(v4sf*)_ps_cephes_exp_C1); - v4sf z = _mm_mul_ps(fx, *(v4sf*)_ps_cephes_exp_C2); - x = _mm_sub_ps(x, tmp); - x = _mm_sub_ps(x, z); - - z = _mm_mul_ps(x,x); - - v4sf y = *(v4sf*)_ps_cephes_exp_p0; - y = _mm_mul_ps(y, x); - y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p1); - y = _mm_mul_ps(y, x); - y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p2); - y = _mm_mul_ps(y, x); - y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p3); - y = _mm_mul_ps(y, x); - y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p4); - y = _mm_mul_ps(y, x); - y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p5); - y = _mm_mul_ps(y, z); - y = _mm_add_ps(y, x); - y = _mm_add_ps(y, one); - - /* build 2^n */ -#ifndef USE_SSE2 - z = _mm_movehl_ps(z, fx); - mm0 = _mm_cvttps_pi32(fx); - mm1 = _mm_cvttps_pi32(z); - mm0 = _mm_add_pi32(mm0, *(v2si*)_pi32_0x7f); - mm1 = _mm_add_pi32(mm1, *(v2si*)_pi32_0x7f); - mm0 = _mm_slli_pi32(mm0, 23); - mm1 = _mm_slli_pi32(mm1, 23); - - v4sf pow2n; - COPY_MM_TO_XMM(mm0, mm1, pow2n); - _mm_empty(); -#else - emm0 = _mm_cvttps_epi32(fx); - emm0 = _mm_add_epi32(emm0, *(v4si*)_pi32_0x7f); - emm0 = _mm_slli_epi32(emm0, 23); - v4sf pow2n = _mm_castsi128_ps(emm0); -#endif - y = _mm_mul_ps(y, pow2n); - return y; -} - -_PS_CONST(minus_cephes_DP1, -0.78515625f); -_PS_CONST(minus_cephes_DP2, -2.4187564849853515625e-4f); -_PS_CONST(minus_cephes_DP3, -3.77489497744594108e-8f); -_PS_CONST(sincof_p0, -1.9515295891E-4f); -_PS_CONST(sincof_p1, 8.3321608736E-3f); -_PS_CONST(sincof_p2, -1.6666654611E-1f); -_PS_CONST(coscof_p0, 2.443315711809948E-005f); -_PS_CONST(coscof_p1, -1.388731625493765E-003f); -_PS_CONST(coscof_p2, 4.166664568298827E-002f); -_PS_CONST(cephes_FOPI, 1.27323954473516f); // 4 / M_PI - - -/* evaluation of 4 sines at onces, using only SSE1+MMX intrinsics so - it runs also on old athlons XPs and the pentium III of your grand - mother. - - The code is the exact rewriting of the cephes sinf function. - Precision is excellent as long as x < 8192 (I did not bother to - take into account the special handling they have for greater values - -- it does not return garbage for arguments over 8192, though, but - the extra precision is missing). - - Note that it is such that sinf((float)M_PI) = 8.74e-8, which is the - surprising but correct result. - - Performance is also surprisingly good, 1.33 times faster than the - macos vsinf SSE2 function, and 1.5 times faster than the - __vrs4_sinf of amd's ACML (which is only available in 64 bits). Not - too bad for an SSE1 function (with no special tuning) ! - However the latter libraries probably have a much better handling of NaN, - Inf, denormalized and other special arguments.. - - On my core 1 duo, the execution of this function takes approximately 95 cycles. - - From what I have observed on the experiments with Intel AMath lib, switching to an - SSE2 version would improve the perf by only 10%. - - Since it is based on SSE intrinsics, it has to be compiled at -O2 to - deliver full speed. -*/ -v4sf sin_ps(v4sf x) { // any x - v4sf xmm1, xmm2 = _mm_setzero_ps(), xmm3, sign_bit, y; - -#ifdef USE_SSE2 - v4si emm0, emm2; -#else - v2si mm0, mm1, mm2, mm3; -#endif - sign_bit = x; - /* take the absolute value */ - x = _mm_and_ps(x, *(v4sf*)_ps_inv_sign_mask); - /* extract the sign bit (upper one) */ - sign_bit = _mm_and_ps(sign_bit, *(v4sf*)_ps_sign_mask); - - /* scale by 4/Pi */ - y = _mm_mul_ps(x, *(v4sf*)_ps_cephes_FOPI); - -#ifdef USE_SSE2 - /* store the integer part of y in mm0 */ - emm2 = _mm_cvttps_epi32(y); - /* j=(j+1) & (~1) (see the cephes sources) */ - emm2 = _mm_add_epi32(emm2, *(v4si*)_pi32_1); - emm2 = _mm_and_si128(emm2, *(v4si*)_pi32_inv1); - y = _mm_cvtepi32_ps(emm2); - - /* get the swap sign flag */ - emm0 = _mm_and_si128(emm2, *(v4si*)_pi32_4); - emm0 = _mm_slli_epi32(emm0, 29); - /* get the polynom selection mask - there is one polynom for 0 <= x <= Pi/4 - and another one for Pi/4 Date: Sun, 31 May 2020 17:10:09 +0200 Subject: [PATCH 27/42] Removed unused config values --- src/sfizz/Config.h | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/src/sfizz/Config.h b/src/sfizz/Config.h index 7e1eaa42..4b0a5b67 100644 --- a/src/sfizz/Config.h +++ b/src/sfizz/Config.h @@ -97,28 +97,4 @@ namespace config { static constexpr double amplitudeSquare = 0.515; } // namespace config -// Enable or disable SIMD accelerators by default -namespace SIMDConfig { - constexpr bool writeInterleaved { true }; - constexpr bool readInterleaved { true }; - constexpr bool fill { true }; - constexpr bool gain { false }; - constexpr bool divide { false }; - constexpr bool mathfuns { false }; - constexpr bool loopingSFZIndex { true }; - constexpr bool saturatingSFZIndex { true }; - constexpr bool linearRamp { false }; - constexpr bool multiplicativeRamp { true }; - constexpr bool add { false }; - constexpr bool subtract { false }; - constexpr bool multiplyAdd { false }; - constexpr bool copy { false }; - constexpr bool pan { false }; - constexpr bool cumsum { true }; - constexpr bool diff { false }; - constexpr bool sfzInterpolationCast { true }; - constexpr bool mean { false }; - constexpr bool meanSquared { false }; - constexpr bool upsampling { true }; -} } // namespace sfz From 1498daa8a6ff8e9ea8ffaf5f3c9f9a44c49cfcff Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 31 May 2020 17:10:26 +0200 Subject: [PATCH 28/42] update tidy script --- scripts/run_clang_tidy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/run_clang_tidy.sh b/scripts/run_clang_tidy.sh index 370171df..e9d7ad53 100755 --- a/scripts/run_clang_tidy.sh +++ b/scripts/run_clang_tidy.sh @@ -29,5 +29,5 @@ clang-tidy \ vst/SfizzVstEditor.cpp \ vst/SfizzVstState.cpp \ -- -Iexternal/abseil-cpp -Isrc/external -Isrc/external/pugixml/src \ - -Isrc/sfizz -Isrc -Isrc/external/spline \ + -Isrc/sfizz -Isrc -Isrc/external/spline -Isrc/external/cpuid/src \ -Ivst -Ivst/external/VST_SDK/VST3_SDK -Ivst/external/VST_SDK/VST3_SDK/vstgui4 -Ivst/external/ring_buffer -DNDEBUG From 87c6174cad0b1eb618077e28542587dccb8c832b Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 31 May 2020 17:25:55 +0200 Subject: [PATCH 29/42] Use a custom lround and silence tidy --- src/sfizz/MathHelpers.h | 14 ++++++++++++++ src/sfizz/Panning.cpp | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/sfizz/MathHelpers.h b/src/sfizz/MathHelpers.h index cf30c79a..4a6aff49 100644 --- a/src/sfizz/MathHelpers.h +++ b/src/sfizz/MathHelpers.h @@ -254,6 +254,20 @@ constexpr Type sqrtTwo() { return static_cast(1.41421356237309504880168872 template constexpr Type sqrtTwoInv() { return static_cast(0.707106781186547524400844362104849039284835937688474036588); }; +/** + * @brief lround for positive values + * This optimizes a bit better by ignoring the negative code path + * + * @tparam T + * @param value + * @return constexpr long int + */ +template::value, int> = 0 > +constexpr long int lroundPositive(T value) +{ + return static_cast(0.5f + value); // NOLINT +} + /** @brief A fraction which is parameterized by integer type */ diff --git a/src/sfizz/Panning.cpp b/src/sfizz/Panning.cpp index bdafebd8..299f2955 100644 --- a/src/sfizz/Panning.cpp +++ b/src/sfizz/Panning.cpp @@ -1,5 +1,6 @@ #include "Panning.h" #include +#include namespace sfz { @@ -24,7 +25,7 @@ static const auto panData = []() float panLookup(float pan) { // reduce range, round to nearest - int index = static_cast(0.5f + pan * (panSize - 1)); + int index = lroundPositive(pan * (panSize - 1)); return panData[index]; } From dfb2212f106c3f2dd76484029cb09991407728e8 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 31 May 2020 17:40:19 +0200 Subject: [PATCH 30/42] Removed unused operations --- src/sfizz/SIMDHelpers.cpp | 3 --- src/sfizz/SIMDHelpers.h | 3 --- 2 files changed, 6 deletions(-) diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index 5fd4d226..2fb5f987 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -26,9 +26,6 @@ void resetSIMDStatus() simdStatus[static_cast(SIMDOps::fill)] = true; simdStatus[static_cast(SIMDOps::gain)] = true; simdStatus[static_cast(SIMDOps::divide)] = false; - simdStatus[static_cast(SIMDOps::mathfuns)] = false; - simdStatus[static_cast(SIMDOps::loopingSFZIndex)] = true; - simdStatus[static_cast(SIMDOps::saturatingSFZIndex)] = true; simdStatus[static_cast(SIMDOps::linearRamp)] = false; simdStatus[static_cast(SIMDOps::multiplicativeRamp)] = true; simdStatus[static_cast(SIMDOps::add)] = false; diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index acc2c526..7c5ad7bc 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -43,9 +43,6 @@ enum class SIMDOps { fill, gain, divide, - mathfuns, - loopingSFZIndex, - saturatingSFZIndex, linearRamp, multiplicativeRamp, add, From e8df9fad55fd810a7f51ac15090d30291138c7f9 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 31 May 2020 18:05:30 +0200 Subject: [PATCH 31/42] Unused operation and bug in multiplicativeRamp --- src/sfizz/SIMDHelpers.cpp | 3 +-- src/sfizz/SIMDHelpers.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index 2fb5f987..40a40e36 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -32,7 +32,6 @@ void resetSIMDStatus() simdStatus[static_cast(SIMDOps::subtract)] = false; simdStatus[static_cast(SIMDOps::multiplyAdd)] = false; simdStatus[static_cast(SIMDOps::copy)] = false; - simdStatus[static_cast(SIMDOps::pan)] = false; simdStatus[static_cast(SIMDOps::cumsum)] = true; simdStatus[static_cast(SIMDOps::diff)] = false; simdStatus[static_cast(SIMDOps::sfzInterpolationCast)] = true; @@ -316,7 +315,7 @@ float multiplicativeRamp(float* output, float start, float step, unsigned { const auto sentinel = output + size; - if (getSIMDOpStatus(SIMDOps::linearRamp)) { + if (getSIMDOpStatus(SIMDOps::multiplicativeRamp)) { #if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 if (cpuInfo.has_sse()) { const auto* lastAligned = prevAligned(sentinel); diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index 7c5ad7bc..2ca4375f 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -49,7 +49,6 @@ enum class SIMDOps { subtract, multiplyAdd, copy, - pan, cumsum, diff, sfzInterpolationCast, From ccfbf3cd1c6912ed239b39de76ed0e74d60ea2a1 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 31 May 2020 18:22:55 +0200 Subject: [PATCH 32/42] Removed inexistant targets from dependencies --- benchmarks/CMakeLists.txt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index ffae6f8c..d36e4547 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -110,27 +110,21 @@ add_dependencies(sfizz_benchmarks bm_read bm_mean bm_meanSquared - bm_fill bm_cumsum bm_diff - bm_interpolationCast bm_mathfuns bm_gain bm_divide - bm_looping - bm_saturating bm_ramp bm_ADSR bm_add bm_logger - bm_pan bm_subtract bm_multiplyAdd bm_readChunk bm_resampleChunk bm_envelopes bm_wavfile - bm_widthPos bm_flacfile bm_filterModulation bm_filterStereoMono From a6417f27c47eb5136944606edf550e6cf6fa8620 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 31 May 2020 19:27:03 +0200 Subject: [PATCH 33/42] Example AVX for the applyGain case It does not help so much though apparently, at least on my machine... --- cmake/SfizzSIMDSourceFiles.cmake | 1 + src/sfizz/SIMDHelpers.cpp | 25 +++++- tests/SIMDHelpersT.cpp | 140 +++++++++++++++++-------------- 3 files changed, 101 insertions(+), 65 deletions(-) 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") From cc7a8e69ccc3bb1f8bf0ae0c29ca270a0ba433e2 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Mon, 1 Jun 2020 09:03:48 +0200 Subject: [PATCH 34/42] Detect AVX compilation --- src/sfizz/SIMDConfig.h | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/sfizz/SIMDConfig.h b/src/sfizz/SIMDConfig.h index c4f77d48..d06d6615 100644 --- a/src/sfizz/SIMDConfig.h +++ b/src/sfizz/SIMDConfig.h @@ -13,19 +13,27 @@ - SFIZZ_HAVE_SSE - SFIZZ_HAVE_SSE2 + - SFIZZ_HAVE_AVX - SFIZZ_HAVE_NEON */ #if defined(__GNUC__) -# if defined(__SSE2__) +# if defined(__AVX__) # define SFIZZ_DETECT_SSE 1 # define SFIZZ_DETECT_SSE2 1 +# define SFIZZ_DETECT_AVX 1 +# elif defined(__SSE2__) +# define SFIZZ_DETECT_SSE 1 +# define SFIZZ_DETECT_SSE2 1 +# define SFIZZ_DETECT_AVX 0 # elif defined(__SSE__) # define SFIZZ_DETECT_SSE 1 # define SFIZZ_DETECT_SSE2 0 +# define SFIZZ_DETECT_AVX 0 # else # define SFIZZ_DETECT_SSE 0 # define SFIZZ_DETECT_SSE2 0 +# define SFIZZ_DETECT_AVX 0 # endif # if defined(__ARM_NEON__) # define SFIZZ_DETECT_NEON 1 @@ -33,15 +41,22 @@ # define SFIZZ_DETECT_NEON 0 # endif #elif defined(_MSC_VER) -# if defined(_M_AMD64) || defined(_M_X64) +# if defined(__AVX__) # define SFIZZ_DETECT_SSE 1 # define SFIZZ_DETECT_SSE2 1 +# define SFIZZ_DETECT_AVX 1 +# elif defined(_M_AMD64) || defined(_M_X64) +# define SFIZZ_DETECT_SSE 1 +# define SFIZZ_DETECT_SSE2 1 +# define SFIZZ_DETECT_AVX 0 # elif _M_IX86_FP == 2 # define SFIZZ_DETECT_SSE 1 # define SFIZZ_DETECT_SSE2 1 +# define SFIZZ_DETECT_AVX 0 # elif _M_IX86_FP == 1 # define SFIZZ_DETECT_SSE 1 # define SFIZZ_DETECT_SSE2 0 +# define SFIZZ_DETECT_AVX 0 # endif // TODO: how to check for NEON on MSVC ARM? #endif @@ -60,6 +75,13 @@ # define SFIZZ_HAVE_SSE2 0 # endif #endif +#ifndef SFIZZ_HAVE_AVX +# ifdef SFIZZ_DETECT_AVX +# define SFIZZ_HAVE_AVX SFIZZ_DETECT_AVX +# else +# define SFIZZ_HAVE_AVX 0 +# endif +#endif #ifndef SFIZZ_HAVE_NEON # ifdef SFIZZ_DETECT_NEON # define SFIZZ_HAVE_NEON SFIZZ_DETECT_NEON From f523a25978c42343ac7d9393c63148f386e881f1 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Mon, 1 Jun 2020 09:12:42 +0200 Subject: [PATCH 35/42] Shuffle things around to better separate SIMD versions from normal code --- cmake/SfizzSIMDSourceFiles.cmake | 6 +- dpf.mk | 2 + scripts/run_clang_tidy.sh | 2 + src/sfizz/SIMDHelpers.cpp | 554 ++++--------------------------- src/sfizz/SIMDHelpers.h | 130 ++------ src/sfizz/simd/Common.h | 34 ++ src/sfizz/simd/HelpersAVX.cpp | 56 ++++ src/sfizz/simd/HelpersAVX.h | 10 + src/sfizz/simd/HelpersSSE.cpp | 471 ++++++++++++++++++++++++++ src/sfizz/simd/HelpersSSE.h | 27 ++ src/sfizz/simd/HelpersScalar.h | 181 ++++++++++ 11 files changed, 876 insertions(+), 597 deletions(-) create mode 100644 src/sfizz/simd/Common.h create mode 100644 src/sfizz/simd/HelpersAVX.cpp create mode 100644 src/sfizz/simd/HelpersAVX.h create mode 100644 src/sfizz/simd/HelpersSSE.cpp create mode 100644 src/sfizz/simd/HelpersSSE.h create mode 100644 src/sfizz/simd/HelpersScalar.h diff --git a/cmake/SfizzSIMDSourceFiles.cmake b/cmake/SfizzSIMDSourceFiles.cmake index efd86bb7..3cc9afdd 100644 --- a/cmake/SfizzSIMDSourceFiles.cmake +++ b/cmake/SfizzSIMDSourceFiles.cmake @@ -2,7 +2,9 @@ macro(sfizz_add_simd_sources SOURCES_VAR PREFIX) # It needs a macro, otherwise the source properties cannot take effect. list (APPEND ${SOURCES_VAR} - ${PREFIX}/sfizz/SIMDHelpers.cpp) + ${PREFIX}/sfizz/SIMDHelpers.cpp + ${PREFIX}/sfizz/simd/HelpersSSE.cpp + ${PREFIX}/sfizz/simd/HelpersAVX.cpp) # For CPU-dispatched X86 sources # Always build them for all X86 targets. @@ -13,7 +15,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 + ${PREFIX}/sfizz/simd/HelpersAVX.cpp PROPERTIES COMPILE_FLAGS "-mavx") endif() endif() diff --git a/dpf.mk b/dpf.mk index e9bfb051..c14758b6 100644 --- a/dpf.mk +++ b/dpf.mk @@ -97,6 +97,8 @@ SFIZZ_SOURCES = \ src/sfizz/SfzFilter.cpp \ src/sfizz/SfzHelpers.cpp \ src/sfizz/SIMDHelpers.cpp \ + src/sfizz/simd/SSEHelpers.cpp \ + src/sfizz/simd/AVXHelpers.cpp \ src/sfizz/Synth.cpp \ src/sfizz/Tuning.cpp \ src/sfizz/Voice.cpp \ diff --git a/scripts/run_clang_tidy.sh b/scripts/run_clang_tidy.sh index e9d7ad53..83998476 100755 --- a/scripts/run_clang_tidy.sh +++ b/scripts/run_clang_tidy.sh @@ -18,6 +18,8 @@ clang-tidy \ src/sfizz/Region.cpp \ src/sfizz/SfzHelpers.cpp \ src/sfizz/SIMDHelpers.cpp \ + src/sfizz/simd/HelpersSSE.cpp \ + src/sfizz/simd/HelpersAVX.cpp \ src/sfizz/Synth.cpp \ src/sfizz/Voice.cpp \ src/sfizz/effects/Eq.cpp \ diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index f495127f..359d025a 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -1,18 +1,16 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + #include "SIMDHelpers.h" #include #include "cpuid/cpuinfo.hpp" - +#include "simd/HelpersSSE.h" +#include "simd/HelpersAVX.h" #include "SIMDConfig.h" -#if SFIZZ_HAVE_SSE2 -#include -#include -#endif - -#if SFIZZ_HAVE_NEON -#include -#endif - namespace sfz { static std::array(SIMDOps::_sentinel)> simdStatus; @@ -57,606 +55,186 @@ bool getSIMDOpStatus(SIMDOps op) return simdStatus[static_cast(op)]; } -constexpr uintptr_t TypeAlignment = 4; - -template -inline void tickRead(const T*& input, T*& outputLeft, T*& outputRight) -{ - *outputLeft++ = *input++; - *outputRight++ = *input++; -} - -template -inline void tickWrite(T*& output, const T*& inputLeft, const T*& inputRight) -{ - *output++ = *inputLeft++; - *output++ = *inputRight++; -} - void readInterleaved(const float* input, float* outputLeft, float* outputRight, unsigned inputSize) noexcept { - const auto sentinel = input + inputSize - 1; - if (getSIMDOpStatus(SIMDOps::readInterleaved)) { -#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 - if (cpuInfo.has_sse()) { - const auto* lastAligned = prevAligned(input + inputSize - 4); - while (unaligned(input, outputLeft, outputRight) && input < lastAligned) - tickRead(input, outputLeft, outputRight); - - while (input < lastAligned) { - auto register0 = _mm_load_ps(input); - auto register1 = _mm_load_ps(input + 4); - auto register2 = register0; - // register 2 holds the copy of register 0 that is going to get erased by the first operation - // Remember that the bit mask reads from the end; 10 00 10 00 means - // "take 0 from a, take 2 from a, take 0 from b, take 2 from b" - register0 = _mm_shuffle_ps(register0, register1, 0b10001000); - register1 = _mm_shuffle_ps(register2, register1, 0b11011101); - _mm_store_ps(outputLeft, register0); - _mm_store_ps(outputRight, register1); - incrementAll<4>(input, input, outputLeft, outputRight); - } - // Fallthrough from lastAligned to sentinel - } -#endif - -#if 0 // NEON wip - auto reg = vld2q_f32(in); - vst1q_f32(lOut, reg.val[0]); - vst1q_f32(rOut, reg.val[1]); -#endif + if (cpuInfo.has_sse()) + return readInterleavedSSE(input, outputLeft, outputRight, inputSize); } - - while (input < sentinel) - tickRead(input, outputLeft, outputRight); + return readInterleavedScalar(input, outputLeft, outputRight, inputSize); } void writeInterleaved(const float* inputLeft, const float* inputRight, float* output, unsigned outputSize) noexcept { - const auto sentinel = output + outputSize - 1; - if (getSIMDOpStatus(SIMDOps::writeInterleaved)) { -#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 - if (cpuInfo.has_sse()) { - const auto* lastAligned = prevAligned(output + outputSize - 4); - - while (unaligned(output, inputRight, inputLeft) && output < lastAligned) - tickWrite(output, inputLeft, inputRight); - - while (output < lastAligned) { - const auto lInRegister = _mm_load_ps(inputLeft); - const auto rInRegister = _mm_load_ps(inputRight); - const auto outRegister1 = _mm_unpacklo_ps(lInRegister, rInRegister); - _mm_store_ps(output, outRegister1); - const auto outRegister2 = _mm_unpackhi_ps(lInRegister, rInRegister); - _mm_store_ps(output + 4, outRegister2); - incrementAll<4>(output, output, inputLeft, inputRight); - } - // fallthrough from lastAligned to sentinel - } -#endif + if (cpuInfo.has_sse()) + return writeInterleavedSSE(inputLeft, inputRight, output, outputSize); } - - while (output < sentinel) - tickWrite(output, inputLeft, inputRight); + return writeInterleavedScalar(inputLeft, inputRight, output, outputSize); } template <> void applyGain(float gain, const float* input, float* output, unsigned size) noexcept { - const auto sentinel = output + size; - if (getSIMDOpStatus(SIMDOps::gain)) { -#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 - 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) - *output++ = gain * (*input++); - - while (output < lastAligned) { - _mm_store_ps(output, _mm_mul_ps(mmGain, _mm_load_ps(input))); - incrementAll<4>(input, output); - } - // fallthrough from lastAligned to sentinel - } -#endif + if (cpuInfo.has_avx()) + return applyGainAVX(gain, input, output, size); + else if (cpuInfo.has_sse()) + return applyGainSSE(gain, input, output, size); } - - while (output < sentinel) - *output++ = gain * (*input++); + return applyGainScalar(gain, input, output, size); } template <> void applyGain(const float* gain, const float* input, float* output, unsigned size) noexcept { - const auto sentinel = output + size; - if (getSIMDOpStatus(SIMDOps::gain)) { -#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 - 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) - *output++ = (*gain++) * (*input++); - - while (output < lastAligned) { - _mm_store_ps(output, _mm_mul_ps(_mm_load_ps(gain), _mm_load_ps(input))); - incrementAll<4>(gain, input, output); - } - // fallthrough from lastAligned to sentinel - } -#endif + if (cpuInfo.has_avx()) + return applyGainAVX(gain, input, output, size); + else if (cpuInfo.has_sse()) + return applyGainSSE(gain, input, output, size); } - - while (output < sentinel) - *output++ = (*gain++) * (*input++); + return applyGainScalar(gain, input, output, size); } template <> void divide(const float* input, const float* divisor, float* output, unsigned size) noexcept { - const auto sentinel = output + size; - if (getSIMDOpStatus(SIMDOps::divide)) { -#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++) / (*divisor++); - - while (output < lastAligned) { - _mm_store_ps(output, _mm_div_ps(_mm_load_ps(input), _mm_load_ps(divisor))); - incrementAll<4>(divisor, input, output); - } - // fallthrough from lastAligned to sentinel - } -#endif + if (cpuInfo.has_sse()) + return divideSSE(input, divisor, output, size); } - - while (output < sentinel) - *output++ = (*input++) / (*divisor++); + return divideScalar(input, divisor, output, size); } template <> void multiplyAdd(const float* gain, const float* input, float* output, unsigned size) noexcept { - const auto sentinel = output + size; - if (getSIMDOpStatus(SIMDOps::multiplyAdd)) { -#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++ += (*gain++) * (*input++); - - while (output < lastAligned) { - auto mmOut = _mm_load_ps(output); - mmOut = _mm_add_ps(_mm_mul_ps(_mm_load_ps(gain), _mm_load_ps(input)), mmOut); - _mm_store_ps(output, mmOut); - incrementAll<4>(gain, input, output); - } - // fallthrough from lastAligned to sentinel - } -#endif + if (cpuInfo.has_sse()) + return multiplyAddSSE(gain, input, output, size); } - - while (output < sentinel) - *output++ += (*gain++) * (*input++); + return multiplyAddScalar(gain, input, output, size); } template <> void multiplyAdd(float gain, const float* input, float* output, unsigned size) noexcept { - const auto sentinel = output + size; - if (getSIMDOpStatus(SIMDOps::multiplyAdd)) { -#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++ += gain * (*input++); - - auto mmGain = _mm_set1_ps(gain); - while (output < lastAligned) { - auto mmOut = _mm_load_ps(output); - mmOut = _mm_add_ps(_mm_mul_ps(mmGain, _mm_load_ps(input)), mmOut); - _mm_store_ps(output, mmOut); - incrementAll<4>(input, output); - } - // fallthrough from lastAligned to sentinel - } -#endif + if (cpuInfo.has_sse()) + return multiplyAddSSE(gain, input, output, size); } - - while (output < sentinel) - *output++ += gain * (*input++); + return multiplyAddScalar(gain, input, output, size); } template <> float linearRamp(float* output, float start, float step, unsigned size) noexcept { - const auto sentinel = output + size; - if (getSIMDOpStatus(SIMDOps::linearRamp)) { -#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++ = start; - start += step; - } - - auto mmStart = _mm_set1_ps(start - step); - auto mmStep = _mm_set_ps(step + step + step + step, step + step + step, step + step, step); - while (output < lastAligned) { - 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); - } - start = _mm_cvtss_f32(mmStart) + step; - // fallthrough from lastAligned to sentinel - } -#endif + if (cpuInfo.has_sse()) + return linearRampSSE(output, start, step, size); } - - while (output < sentinel) { - *output++ = start; - start += step; - } - return start; + return linearRampScalar(output, start, step, size); } template <> float multiplicativeRamp(float* output, float start, float step, unsigned size) noexcept { - const auto sentinel = output + size; - if (getSIMDOpStatus(SIMDOps::multiplicativeRamp)) { -#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++ = start; - start *= step; - } - - auto mmStart = _mm_set1_ps(start / step); - auto mmStep = _mm_set_ps(step * step * step * step, step * step * step, step * step, step); - while (output < lastAligned) { - 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); - } - start = _mm_cvtss_f32(mmStart) * step; - // fallthrough from lastAligned to sentinel - } -#endif + if (cpuInfo.has_sse()) + return multiplicativeRampSSE(output, start, step, size); } - - while (output < sentinel) { - *output++ = start; - start *= step; - } - return start; + return multiplicativeRampScalar(output, start, step, size); } 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 + if (cpuInfo.has_sse()) + return addSSE(input, output, size); } - - while (output < sentinel) - *output++ += *input++; + return addScalar(input, output, size); } 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 + if (cpuInfo.has_sse()) + return addSSE(value, output, size); } - - while (output < sentinel) - *output++ += value; + return addScalar(value, output, size); } template <> void subtract(const float* input, float* output, unsigned size) noexcept { - const auto sentinel = output + size; - if (getSIMDOpStatus(SIMDOps::subtract)) { -#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_sub_ps(_mm_load_ps(output), _mm_load_ps(input))); - incrementAll<4>(input, output); - } - // fallthrough from lastAligned to sentinel - } -#endif + if (cpuInfo.has_sse()) + return subtractSSE(input, output, size); } - - while (output < sentinel) - *output++ -= *input++; + return subtractScalar(input, output, size); } template <> void subtract(float value, float* output, unsigned size) noexcept { - const auto sentinel = output + size; - if (getSIMDOpStatus(SIMDOps::subtract)) { -#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_sub_ps(_mm_load_ps(output), mmValue)); - incrementAll<4>(output); - } - // fallthrough from lastAligned to sentinel - } -#endif + if (cpuInfo.has_sse()) + return subtractSSE(value, output, size); } - - while (output < sentinel) - *output++ -= value; + return subtractScalar(value, output, size); } template <> void copy(const float* input, float* output, unsigned size) noexcept { - // The sentinel is the input here - const auto sentinel = input + size; - if (getSIMDOpStatus(SIMDOps::copy)) { -#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 - if (cpuInfo.has_sse()) { - const auto* lastAligned = prevAligned(sentinel); - - while (unaligned(input, output) && input < lastAligned) - *output++ = *input++; - - while (input < lastAligned) { - _mm_store_ps(output, _mm_load_ps(input)); - incrementAll<4>(input, output); - } - // fallthrough from lastAligned to sentinel - } -#endif + if (cpuInfo.has_sse()) + return copySSE(input, output, size); } - - std::copy(input, sentinel, output); + std::copy(input, input + size, output); } template <> float mean(const float* vector, unsigned size) noexcept { - const auto sentinel = vector + size; - - float result { 0.0f }; - if (size == 0) - return result; - if (getSIMDOpStatus(SIMDOps::mean)) { -#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 - if (cpuInfo.has_sse()) { - const auto* lastAligned = prevAligned(sentinel); - while (unaligned(vector) && vector < lastAligned) - result += *vector++; - - auto mmSums = _mm_setzero_ps(); - while (vector < lastAligned) { - mmSums = _mm_add_ps(mmSums, _mm_load_ps(vector)); - incrementAll<4>(vector); - } - - std::array sseResult; - _mm_store_ps(sseResult.data(), mmSums); - - for (auto sseValue : sseResult) - result += sseValue; - - // fallthrough from lastAligned to sentinel - } -#endif + if (cpuInfo.has_sse()) + return meanSSE(vector, size); } - - while (vector < sentinel) - result += *vector++; - - return result / static_cast(size); + return meanScalar(vector, size); } template <> float meanSquared(const float* vector, unsigned size) noexcept { - const auto sentinel = vector + size; - - float result { 0.0f }; - if (size == 0) - return result; - if (getSIMDOpStatus(SIMDOps::meanSquared)) { -#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 - if (cpuInfo.has_sse()) { - const auto* lastAligned = prevAligned(sentinel); - while (unaligned(vector) && vector < lastAligned){ - result += (*vector) * (*vector); - vector++; + if (cpuInfo.has_sse()) + return meanSquaredSSE(vector, size); } - - auto mmSums = _mm_setzero_ps(); - while (vector < lastAligned) { - const auto mmValues = _mm_load_ps(vector); - mmSums = _mm_add_ps(mmSums, _mm_mul_ps(mmValues, mmValues)); - incrementAll<4>(vector); - } - - std::array sseResult; - _mm_store_ps(sseResult.data(), mmSums); - - for (auto sseValue : sseResult) - result += sseValue; - - // fallthrough from lastAligned to sentinel - } -#endif - } - - while (vector < sentinel) { - result += (*vector) * (*vector); - vector++; - } - - return result / static_cast(size); + return meanSquaredScalar(vector, size); } template <> void cumsum(const float* input, float* output, unsigned size) noexcept { - if (size == 0) - return; - - const auto sentinel = output + size; - *output++ = *input++; - if (getSIMDOpStatus(SIMDOps::cumsum)) { -#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 = *(output - 1) + *input; - incrementAll(input, output); - } - - auto mmOutput = _mm_set_ps1(*(output - 1)); - while (output < lastAligned) { - auto mmOffset = _mm_load_ps(input); - mmOffset = _mm_add_ps(mmOffset, _mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(mmOffset), 4))); - mmOffset = _mm_add_ps(mmOffset, _mm_shuffle_ps(_mm_setzero_ps(), mmOffset, _MM_SHUFFLE(1, 0, 0, 0))); - mmOutput = _mm_add_ps(mmOutput, mmOffset); - _mm_store_ps(output, mmOutput); - mmOutput = _mm_shuffle_ps(mmOutput, mmOutput, _MM_SHUFFLE(3, 3, 3, 3)); - incrementAll<4>(input, output); - } - // fallthrough from lastAligned to sentinel - } -#endif - } - - while (output < sentinel) { - *output = *(output - 1) + *input; - incrementAll(input, output); + if (cpuInfo.has_sse()) + return cumsumSSE(input, output, size); } + return cumsumScalar(input, output, size); } 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); + if (cpuInfo.has_sse()) + return diffSSE(input, output, size); } + return diffScalar(input, output, size); } } diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index 2ca4375f..9e3bd06b 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -27,7 +27,7 @@ #include "Config.h" #include "Debug.h" #include "MathHelpers.h" -#include +#include "simd/HelpersScalar.h" #include #include #include @@ -62,32 +62,6 @@ enum class SIMDOps { void setSIMDOpStatus(SIMDOps op, bool status); bool getSIMDOpStatus(SIMDOps op); -constexpr uintptr_t ByteAlignmentMask(unsigned N) { return N - 1; } - -template -T* nextAligned(const T* ptr) -{ - return reinterpret_cast(reinterpret_cast(ptr) + ByteAlignmentMask(N) & (~ByteAlignmentMask(N))); -} - -template -T* prevAligned(const T* ptr) -{ - return reinterpret_cast(reinterpret_cast(ptr) & (~ByteAlignmentMask(N))); -} - -template -bool unaligned(const T* ptr) -{ - return (reinterpret_cast(ptr) & ByteAlignmentMask(N) )!= 0; -} - -template -bool unaligned(const T* ptr1, Args... rest) -{ - return unaligned(ptr1) || unaligned(rest...); -} - /** * @brief Read interleaved stereo data from a buffer and separate it in a left/right pair of buffers. * @@ -133,10 +107,16 @@ inline void writeInterleaved(absl::Span inputLeft, absl::Span +void fill(T* output, T value, unsigned size) noexcept +{ + std::fill(output, output + size, value); +} + template void fill(absl::Span output, T value) noexcept { - absl::c_fill(output, value); + fill(output.data(), value, output.size()); } /** @@ -150,9 +130,7 @@ void fill(absl::Span output, T value) noexcept template void applyGain(T gain, const T* input, T* output, unsigned size) noexcept { - const auto sentinel = output + size; - while (output < sentinel) - *output++ = gain * (*input++); + applyGainScalar(gain, input, output, size); } template<> @@ -195,9 +173,7 @@ inline void applyGain(float gain, absl::Span array) noexcept template void applyGain(const T* gain, const T* input, T* output, unsigned size) noexcept { - const auto sentinel = output + size; - while (output < sentinel) - *output++ = (*gain++) * (*input++); + applyGainScalar(gain, input, output, size); } template<> @@ -244,9 +220,7 @@ inline void applyGain(absl::Span gain, absl::Span array) noexcept template void divide(const T* input, const T* divisor, T* output, unsigned size) noexcept { - const auto sentinel = output + size; - while (output < sentinel) - *output++ = (*input++) / (*divisor++); + divideScalar(input, divisor, output, size); } template <> @@ -285,9 +259,7 @@ void divide(absl::Span output, absl::Span divisor) noexcept template void multiplyAdd(const T* gain, const T* input, T* output, unsigned size) noexcept { - const auto sentinel = output + size; - while (output < sentinel) - *output++ += (*gain++) * (*input++); + multiplyAddScalar(gain, input, output, size); } template <> @@ -312,9 +284,7 @@ void multiplyAdd(absl::Span gain, absl::Span input, absl::Span template void multiplyAdd(T gain, const T* input, T* output, unsigned size) noexcept { - const auto sentinel = output + size; - while (output < sentinel) - *output++ += gain * (*input++); + multiplyAddScalar(gain, input, output, size); } template <> @@ -340,12 +310,7 @@ void multiplyAdd(T gain, absl::Span input, absl::Span output) noexce template T linearRamp(T* output, T start, T step, unsigned size) noexcept { - const auto sentinel = output + size; - while (output < sentinel) { - *output++ = start; - start += step; - } - return start; + linearRampScalar(output, start, step, size); } template <> @@ -369,12 +334,7 @@ T linearRamp(absl::Span output, T start, T step) noexcept template T multiplicativeRamp(T* output, T start, T step, unsigned size) noexcept { - const auto sentinel = output + size; - while (output < sentinel) { - *output++ = start; - start *= step; - } - return start; + multiplicativeRampScalar(output, start, step, size); } template <> @@ -398,9 +358,7 @@ T multiplicativeRamp(absl::Span output, T start, T step) noexcept template void add(const T* input, T* output, unsigned size) noexcept { - const auto sentinel = output + size; - while (output < sentinel) - *output++ += *input++; + addScalar(input, output, size); } template <> @@ -424,9 +382,7 @@ void add(absl::Span input, absl::Span output) noexcept template void add(T value, T* output, unsigned size) noexcept { - const auto sentinel = output + size; - while (output < sentinel) - *output++ += value; + addScalar(value, output, size); } template <> @@ -449,9 +405,7 @@ void add(T value, absl::Span output) noexcept template void subtract(const T* input, T* output, unsigned size) noexcept { - const auto sentinel = output + size; - while (output < sentinel) - *output++ -= *input++; + subtractScalar(input, output, size); } template <> @@ -475,9 +429,7 @@ void subtract(absl::Span input, absl::Span output) noexcept template void subtract(T value, T* output, unsigned size) noexcept { - const auto sentinel = output + size; - while (output < sentinel) - *output++ -= value; + subtractScalar(value, output, size); } template <> @@ -525,15 +477,7 @@ void copy(absl::Span input, absl::Span output) noexcept template T mean(const T* vector, unsigned size) noexcept { - T result{ 0.0 }; - if (size == 0) - return result; - - const auto sentinel = vector + size; - while (vector < sentinel) - result += *vector++; - - return result / static_cast(size); + meanScalar(vector, size); } template <> @@ -556,17 +500,7 @@ T mean(absl::Span vector) noexcept template T meanSquared(const T* vector, unsigned size) noexcept { - T result{ 0.0 }; - if (size == 0) - return result; - - const auto sentinel = vector + size; - while (vector < sentinel) { - result += (*vector) * (*vector); - vector++; - } - - return result / static_cast(size); + meanSquaredScalar(vector, size); } template <> @@ -590,16 +524,7 @@ T meanSquared(absl::Span vector) noexcept template void cumsum(const T* input, T* output, unsigned size) noexcept { - if (size == 0) - return; - - const auto sentinel = output + size; - - *output++ = *input++; - while (output < sentinel) { - *output = *(output - 1) + *input; - incrementAll(input, output); - } + cumsumScalar(input, output, size); } template <> @@ -661,16 +586,7 @@ void sfzInterpolationCast(absl::Span floatJumps, absl::Span jumps, template void diff(const T* input, T* output, unsigned size) noexcept { - if (size == 0) - return; - - const auto sentinel = output + size; - - *output++ = *input++; - while (output < sentinel) { - *output = *input - *(input - 1); - incrementAll(input, output); - } + diffScalar(input, output, size); } template <> diff --git a/src/sfizz/simd/Common.h b/src/sfizz/simd/Common.h new file mode 100644 index 00000000..6fdddeab --- /dev/null +++ b/src/sfizz/simd/Common.h @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include + +constexpr uintptr_t ByteAlignmentMask(unsigned N) { return N - 1; } + +template +T* nextAligned(const T* ptr) +{ + return reinterpret_cast(reinterpret_cast(ptr) + ByteAlignmentMask(N) & (~ByteAlignmentMask(N))); +} + +template +T* prevAligned(const T* ptr) +{ + return reinterpret_cast(reinterpret_cast(ptr) & (~ByteAlignmentMask(N))); +} + +template +bool unaligned(const T* ptr) +{ + return (reinterpret_cast(ptr) & ByteAlignmentMask(N) )!= 0; +} + +template +bool unaligned(const T* ptr1, Args... rest) +{ + return unaligned(ptr1) || unaligned(rest...); +} diff --git a/src/sfizz/simd/HelpersAVX.cpp b/src/sfizz/simd/HelpersAVX.cpp new file mode 100644 index 00000000..9ca89a65 --- /dev/null +++ b/src/sfizz/simd/HelpersAVX.cpp @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "HelpersAVX.h" +#include "SIMDConfig.h" +#include "../MathHelpers.h" +#include "Common.h" + +#ifdef SFIZZ_HAVE_AVX +#include "immintrin.h" +using Type = float; +constexpr unsigned TypeAlignment = 8; +constexpr unsigned ByteAlignment = TypeAlignment * sizeof(Type); +#endif + +void applyGainAVX(float gain, const float* input, float* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + +#ifdef SFIZZ_HAVE_AVX + const auto* lastAligned = prevAligned(sentinel); + const auto mmGain = _mm256_set1_ps(gain); + while (unaligned(input, output) && output < lastAligned) + *output++ = gain * (*input++); + + while (output < lastAligned) { + _mm256_store_ps(output, _mm256_mul_ps(mmGain, _mm256_load_ps(input))); + incrementAll(input, output); + } +#endif + + while (output < sentinel) + *output++ = gain * (*input++); +} + +void applyGainAVX(const float* gain, const float* input, float* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + +#ifdef SFIZZ_HAVE_AVX + const auto* lastAligned = prevAligned(sentinel); + while (unaligned(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(input, output); + } +#endif + + while (output < sentinel) + *output++ = (*gain++) * (*input++); +} diff --git a/src/sfizz/simd/HelpersAVX.h b/src/sfizz/simd/HelpersAVX.h new file mode 100644 index 00000000..7eb8c2bf --- /dev/null +++ b/src/sfizz/simd/HelpersAVX.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once + +void applyGainAVX(float gain, const float* input, float* output, unsigned size) noexcept; +void applyGainAVX(const float* gain, const float* input, float* output, unsigned size) noexcept; diff --git a/src/sfizz/simd/HelpersSSE.cpp b/src/sfizz/simd/HelpersSSE.cpp new file mode 100644 index 00000000..8275280a --- /dev/null +++ b/src/sfizz/simd/HelpersSSE.cpp @@ -0,0 +1,471 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "HelpersSSE.h" +#include "../MathHelpers.h" +#include "../SIMDConfig.h" +#include "Common.h" + +#ifdef SFIZZ_HAVE_SSE +#include "emmintrin.h" +using Type = float; +constexpr unsigned TypeAlignment = 4; +constexpr unsigned ByteAlignment = TypeAlignment * sizeof(Type); +#endif + +void readInterleavedSSE(const float* input, float* outputLeft, float* outputRight, unsigned inputSize) noexcept +{ + const auto sentinel = input + inputSize - 1; + +#ifdef SFIZZ_HAVE_SSE + const auto* lastAligned = prevAligned(input + inputSize - TypeAlignment); + while (unaligned(input, outputLeft, outputRight) && input < lastAligned) { + *outputLeft++ = *input++; + *outputRight++ = *input++; + } + + while (input < lastAligned) { + auto register0 = _mm_load_ps(input); + auto register1 = _mm_load_ps(input + TypeAlignment); + auto register2 = register0; + // register 2 holds the copy of register 0 that is going to get erased by the first operation + // Remember that the bit mask reads from the end; 10 00 10 00 means + // "take 0 from a, take 2 from a, take 0 from b, take 2 from b" + register0 = _mm_shuffle_ps(register0, register1, 0b10001000); + register1 = _mm_shuffle_ps(register2, register1, 0b11011101); + _mm_store_ps(outputLeft, register0); + _mm_store_ps(outputRight, register1); + incrementAll(input, input, outputLeft, outputRight); + } + + // NEON wip + // auto reg = vld2q_f32(in); + // vst1q_f32(lOut, reg.val[0]); + // vst1q_f32(rOut, reg.val[1]); +#endif + while (input < sentinel) { + *outputLeft++ = *input++; + *outputRight++ = *input++; + } +} + +void writeInterleavedSSE(const float* inputLeft, const float* inputRight, float* output, unsigned outputSize) noexcept +{ + const auto sentinel = output + outputSize - 1; + +#ifdef SFIZZ_HAVE_SSE + const auto* lastAligned = prevAligned(output + outputSize - TypeAlignment); + while (unaligned(output, inputRight, inputLeft) && output < lastAligned) { + *output++ = *inputLeft++; + *output++ = *inputRight++; + } + + while (output < lastAligned) { + const auto lInRegister = _mm_load_ps(inputLeft); + const auto rInRegister = _mm_load_ps(inputRight); + const auto outRegister1 = _mm_unpacklo_ps(lInRegister, rInRegister); + _mm_store_ps(output, outRegister1); + const auto outRegister2 = _mm_unpackhi_ps(lInRegister, rInRegister); + _mm_store_ps(output + 4, outRegister2); + incrementAll(output, output, inputLeft, inputRight); + } +#endif + + while (output < sentinel) { + *output++ = *inputLeft++; + *output++ = *inputRight++; + } +} + +void applyGainSSE(float gain, const float* input, float* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + +#ifdef SFIZZ_HAVE_SSE + const auto* lastAligned = prevAligned(sentinel); + const auto mmGain = _mm_set1_ps(gain); + while (unaligned(input, output) && output < lastAligned) + *output++ = gain * (*input++); + + while (output < lastAligned) { + _mm_store_ps(output, _mm_mul_ps(mmGain, _mm_load_ps(input))); + incrementAll(input, output); + } +#endif + + while (output < sentinel) + *output++ = gain * (*input++); +} + +void applyGainSSE(const float* gain, const float* input, float* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + +#ifdef SFIZZ_HAVE_SSE + const auto* lastAligned = prevAligned(sentinel); + while (unaligned(input, output) && output < lastAligned) + *output++ = (*gain++) * (*input++); + + while (output < lastAligned) { + _mm_store_ps(output, _mm_mul_ps(_mm_load_ps(gain), _mm_load_ps(input))); + incrementAll(gain, input, output); + } +#endif + + while (output < sentinel) + *output++ = (*gain++) * (*input++); +} + +void divideSSE(const float* input, const float* divisor, float* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + + const auto* lastAligned = prevAligned(sentinel); + + while (unaligned(input, output) && output < lastAligned) + *output++ = (*input++) / (*divisor++); + + while (output < lastAligned) { + _mm_store_ps(output, _mm_div_ps(_mm_load_ps(input), _mm_load_ps(divisor))); + incrementAll(divisor, input, output); + } + + while (output < sentinel) + *output++ = (*input++) / (*divisor++); +} + +void multiplyAddSSE(const float* gain, const float* input, float* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + +#ifdef SFIZZ_HAVE_SSE + const auto* lastAligned = prevAligned(sentinel); + while (unaligned(input, output) && output < lastAligned) + *output++ += (*gain++) * (*input++); + + while (output < lastAligned) { + auto mmOut = _mm_load_ps(output); + mmOut = _mm_add_ps(_mm_mul_ps(_mm_load_ps(gain), _mm_load_ps(input)), mmOut); + _mm_store_ps(output, mmOut); + incrementAll(gain, input, output); + } +#endif + + while (output < sentinel) + *output++ += (*gain++) * (*input++); +} + +void multiplyAddSSE(float gain, const float* input, float* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + +#ifdef SFIZZ_HAVE_SSE + const auto* lastAligned = prevAligned(sentinel); + while (unaligned(input, output) && output < lastAligned) + *output++ += gain * (*input++); + + auto mmGain = _mm_set1_ps(gain); + while (output < lastAligned) { + auto mmOut = _mm_load_ps(output); + mmOut = _mm_add_ps(_mm_mul_ps(mmGain, _mm_load_ps(input)), mmOut); + _mm_store_ps(output, mmOut); + incrementAll(input, output); + } +#endif + + while (output < sentinel) + *output++ += gain * (*input++); +} + +float linearRampSSE(float* output, float start, float step, unsigned size) noexcept +{ + const auto sentinel = output + size; + +#ifdef SFIZZ_HAVE_SSE + const auto* lastAligned = prevAligned(sentinel); + while (unaligned(output) && output < lastAligned) { + *output++ = start; + start += step; + } + + auto mmStart = _mm_set1_ps(start - step); + auto mmStep = _mm_set_ps(step + step + step + step, step + step + step, step + step, step); + while (output < lastAligned) { + mmStart = _mm_add_ps(mmStart, mmStep); + _mm_store_ps(output, mmStart); + mmStart = _mm_shuffle_ps(mmStart, mmStart, _MM_SHUFFLE(3, 3, 3, 3)); + incrementAll(output); + } + start = _mm_cvtss_f32(mmStart) + step; +#endif + + while (output < sentinel) { + *output++ = start; + start += step; + } + return start; +} + +float multiplicativeRampSSE(float* output, float start, float step, unsigned size) noexcept +{ + const auto sentinel = output + size; + +#ifdef SFIZZ_HAVE_SSE + const auto* lastAligned = prevAligned(sentinel); + while (unaligned(output) && output < lastAligned) { + *output++ = start; + start *= step; + } + + auto mmStart = _mm_set1_ps(start / step); + auto mmStep = _mm_set_ps(step * step * step * step, step * step * step, step * step, step); + while (output < lastAligned) { + mmStart = _mm_mul_ps(mmStart, mmStep); + _mm_store_ps(output, mmStart); + mmStart = _mm_shuffle_ps(mmStart, mmStart, _MM_SHUFFLE(3, 3, 3, 3)); + incrementAll(output); + } + start = _mm_cvtss_f32(mmStart) * step; +#endif + + while (output < sentinel) { + *output++ = start; + start *= step; + } + return start; +} + +void addSSE(const float* input, float* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + +#ifdef SFIZZ_HAVE_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(input, output); + } +#endif + + while (output < sentinel) + *output++ += *input++; +} + +void addSSE(float value, float* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + +#ifdef SFIZZ_HAVE_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(output); + } +#endif + + while (output < sentinel) + *output++ += value; +} + +void subtractSSE(const float* input, float* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + +#ifdef SFIZZ_HAVE_SSE + const auto* lastAligned = prevAligned(sentinel); + while (unaligned(input, output) && output < lastAligned) + *output++ -= *input++; + + while (output < lastAligned) { + _mm_store_ps(output, _mm_sub_ps(_mm_load_ps(output), _mm_load_ps(input))); + incrementAll(input, output); + } +#endif + + while (output < sentinel) + *output++ -= *input++; +} + +void subtractSSE(float value, float* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + +#ifdef SFIZZ_HAVE_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_sub_ps(_mm_load_ps(output), mmValue)); + incrementAll(output); + } +#endif + + while (output < sentinel) + *output++ -= value; +} + +void copySSE(const float* input, float* output, unsigned size) noexcept +{ + // The sentinel is the input here + const auto sentinel = input + size; + +#ifdef SFIZZ_HAVE_SSE + const auto* lastAligned = prevAligned(sentinel); + while (unaligned(input, output) && input < lastAligned) + *output++ = *input++; + + while (input < lastAligned) { + _mm_store_ps(output, _mm_load_ps(input)); + incrementAll(input, output); + } +#endif + + std::copy(input, sentinel, output); +} + +float meanSSE(const float* vector, unsigned size) noexcept +{ + const auto sentinel = vector + size; + + float result { 0.0f }; + if (size == 0) + return result; + +#ifdef SFIZZ_HAVE_SSE + const auto* lastAligned = prevAligned(sentinel); + while (unaligned(vector) && vector < lastAligned) + result += *vector++; + + auto mmSums = _mm_setzero_ps(); + while (vector < lastAligned) { + mmSums = _mm_add_ps(mmSums, _mm_load_ps(vector)); + incrementAll(vector); + } + + std::array sseResult; + _mm_store_ps(sseResult.data(), mmSums); + + for (auto sseValue : sseResult) + result += sseValue; +#endif + + while (vector < sentinel) + result += *vector++; + + return result / static_cast(size); +} + +float meanSquaredSSE(const float* vector, unsigned size) noexcept +{ + const auto sentinel = vector + size; + + float result { 0.0f }; + if (size == 0) + return result; + +#ifdef SFIZZ_HAVE_SSE + const auto* lastAligned = prevAligned(sentinel); + while (unaligned(vector) && vector < lastAligned) { + result += (*vector) * (*vector); + vector++; + } + + auto mmSums = _mm_setzero_ps(); + while (vector < lastAligned) { + const auto mmValues = _mm_load_ps(vector); + mmSums = _mm_add_ps(mmSums, _mm_mul_ps(mmValues, mmValues)); + incrementAll(vector); + } + + std::array sseResult; + _mm_store_ps(sseResult.data(), mmSums); + + for (auto sseValue : sseResult) + result += sseValue; +#endif + + while (vector < sentinel) { + result += (*vector) * (*vector); + vector++; + } + + return result / static_cast(size); +} + +void cumsumSSE(const float* input, float* output, unsigned size) noexcept +{ + if (size == 0) + return; + + const auto sentinel = output + size; + *output++ = *input++; + +#ifdef SFIZZ_HAVE_SSE + const auto* lastAligned = prevAligned(sentinel); + while (unaligned(input, output) && output < lastAligned) { + *output = *(output - 1) + *input; + incrementAll(input, output); + } + + auto mmOutput = _mm_set_ps1(*(output - 1)); + while (output < lastAligned) { + auto mmOffset = _mm_load_ps(input); + mmOffset = _mm_add_ps(mmOffset, _mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(mmOffset), 4))); + mmOffset = _mm_add_ps(mmOffset, _mm_shuffle_ps(_mm_setzero_ps(), mmOffset, _MM_SHUFFLE(1, 0, 0, 0))); + mmOutput = _mm_add_ps(mmOutput, mmOffset); + _mm_store_ps(output, mmOutput); + mmOutput = _mm_shuffle_ps(mmOutput, mmOutput, _MM_SHUFFLE(3, 3, 3, 3)); + incrementAll(input, output); + } +#endif + + while (output < sentinel) { + *output = *(output - 1) + *input; + incrementAll(input, output); + } +} + +void diffSSE(const float* input, float* output, unsigned size) noexcept +{ + if (size == 0) + return; + + const auto sentinel = output + size; + *output++ = *input++; + +#ifdef SFIZZ_HAVE_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(input, output); + } +#endif + + while (output < sentinel) { + *output = *input - *(input - 1); + incrementAll(input, output); + } +} diff --git a/src/sfizz/simd/HelpersSSE.h b/src/sfizz/simd/HelpersSSE.h new file mode 100644 index 00000000..9c43e342 --- /dev/null +++ b/src/sfizz/simd/HelpersSSE.h @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once + +/* These are the SSE versions of the SIMDHelpers */ +void readInterleavedSSE(const float* input, float* outputLeft, float* outputRight, unsigned inputSize) noexcept; +void writeInterleavedSSE(const float* inputLeft, const float* inputRight, float* output, unsigned outputSize) noexcept; +void applyGainSSE(float gain, const float* input, float* output, unsigned size) noexcept; +void applyGainSSE(const float* gain, const float* input, float* output, unsigned size) noexcept; +void divideSSE(const float* input, const float* divisor, float* output, unsigned size) noexcept; +void multiplyAddSSE(const float* gain, const float* input, float* output, unsigned size) noexcept; +void multiplyAddSSE(float gain, const float* input, float* output, unsigned size) noexcept; +float linearRampSSE(float* output, float start, float step, unsigned size) noexcept; +float multiplicativeRampSSE(float* output, float start, float step, unsigned size) noexcept; +void addSSE(const float* input, float* output, unsigned size) noexcept; +void addSSE(float value, float* output, unsigned size) noexcept; +void subtractSSE(const float* input, float* output, unsigned size) noexcept; +void subtractSSE(float value, float* output, unsigned size) noexcept; +void copySSE(const float* input, float* output, unsigned size) noexcept; +float meanSSE(const float* vector, unsigned size) noexcept; +float meanSquaredSSE(const float* vector, unsigned size) noexcept; +void cumsumSSE(const float* input, float* output, unsigned size) noexcept; +void diffSSE(const float* input, float* output, unsigned size) noexcept; diff --git a/src/sfizz/simd/HelpersScalar.h b/src/sfizz/simd/HelpersScalar.h new file mode 100644 index 00000000..1554e636 --- /dev/null +++ b/src/sfizz/simd/HelpersScalar.h @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once + +template +inline void readInterleavedScalar(const T* input, T* outputLeft, T* outputRight, unsigned inputSize) +{ + const auto sentinel = input + inputSize - 1; + while (input < sentinel) { + *outputLeft++ = *input++; + *outputRight++ = *input++; + } +} + +template +inline void writeInterleavedScalar(const T* inputLeft, const T* inputRight, T* output, unsigned outputSize) +{ + const auto sentinel = output + outputSize - 1; + while (output < sentinel) { + *output++ = *inputLeft++; + *output++ = *inputRight++; + } +} + +template +inline void applyGainScalar(T gain, const T* input, T* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + while (output < sentinel) + *output++ = gain * (*input++); +} + +template +inline void applyGainScalar(const T* gain, const T* input, T* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + while (output < sentinel) + *output++ = (*gain++) * (*input++); +} + +template +inline void divideScalar(const T* input, const T* divisor, T* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + while (output < sentinel) + *output++ = (*input++) / (*divisor++); +} + +template +inline void multiplyAddScalar(const T* gain, const T* input, T* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + while (output < sentinel) + *output++ += (*gain++) * (*input++); +} + +template +inline void multiplyAddScalar(T gain, const T* input, T* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + while (output < sentinel) + *output++ += gain * (*input++); +} + +template +T linearRampScalar(T* output, T start, T step, unsigned size) noexcept +{ + const auto sentinel = output + size; + while (output < sentinel) { + *output++ = start; + start += step; + } + return start; +} + +template +T multiplicativeRampScalar(T* output, T start, T step, unsigned size) noexcept +{ + const auto sentinel = output + size; + while (output < sentinel) { + *output++ = start; + start *= step; + } + return start; +} + +template +inline void addScalar(const T* input, T* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + while (output < sentinel) + *output++ += *input++; +} + +template +inline void addScalar(T value, T* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + while (output < sentinel) + *output++ += value; +} + +template +inline void subtractScalar(const T* input, T* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + while (output < sentinel) + *output++ -= *input++; +} + +template +inline void subtractScalar(T value, T* output, unsigned size) noexcept +{ + const auto sentinel = output + size; + while (output < sentinel) + *output++ -= value; +} + +template +T meanScalar(const T* vector, unsigned size) noexcept +{ + T result{ 0.0 }; + if (size == 0) + return result; + + const auto sentinel = vector + size; + while (vector < sentinel) + result += *vector++; + + return result / static_cast(size); +} + +template +T meanSquaredScalar(const T* vector, unsigned size) noexcept +{ + T result{ 0.0 }; + if (size == 0) + return result; + + const auto sentinel = vector + size; + while (vector < sentinel) { + result += (*vector) * (*vector); + vector++; + } + + return result / static_cast(size); +} + +template +void cumsumScalar(const T* input, T* output, unsigned size) noexcept +{ + if (size == 0) + return; + + const auto sentinel = output + size; + + *output++ = *input++; + while (output < sentinel) { + *output = *(output - 1) + *input; + incrementAll(input, output); + } +} + +template +void diffScalar(const T* input, T* output, unsigned size) noexcept +{ + if (size == 0) + return; + + const auto sentinel = output + size; + + *output++ = *input++; + while (output < sentinel) { + *output = *input - *(input - 1); + incrementAll(input, output); + } +} From 6e241fe93aca2ae6c011c05bf6856e49858c31d4 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Mon, 1 Jun 2020 09:31:23 +0200 Subject: [PATCH 36/42] CI help and correct DPF names --- dpf.mk | 4 ++-- src/sfizz/SIMDHelpers.cpp | 2 +- src/sfizz/simd/HelpersSSE.cpp | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/dpf.mk b/dpf.mk index c14758b6..772dd364 100644 --- a/dpf.mk +++ b/dpf.mk @@ -97,8 +97,8 @@ SFIZZ_SOURCES = \ src/sfizz/SfzFilter.cpp \ src/sfizz/SfzHelpers.cpp \ src/sfizz/SIMDHelpers.cpp \ - src/sfizz/simd/SSEHelpers.cpp \ - src/sfizz/simd/AVXHelpers.cpp \ + src/sfizz/simd/HelpersSSE.cpp \ + src/sfizz/simd/HelpersAVX.cpp \ src/sfizz/Synth.cpp \ src/sfizz/Tuning.cpp \ src/sfizz/Voice.cpp \ diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index 359d025a..de2e501d 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -7,9 +7,9 @@ #include "SIMDHelpers.h" #include #include "cpuid/cpuinfo.hpp" +#include "SIMDConfig.h" #include "simd/HelpersSSE.h" #include "simd/HelpersAVX.h" -#include "SIMDConfig.h" namespace sfz { diff --git a/src/sfizz/simd/HelpersSSE.cpp b/src/sfizz/simd/HelpersSSE.cpp index 8275280a..bacda811 100644 --- a/src/sfizz/simd/HelpersSSE.cpp +++ b/src/sfizz/simd/HelpersSSE.cpp @@ -8,6 +8,7 @@ #include "../MathHelpers.h" #include "../SIMDConfig.h" #include "Common.h" +#include #ifdef SFIZZ_HAVE_SSE #include "emmintrin.h" @@ -46,6 +47,7 @@ void readInterleavedSSE(const float* input, float* outputLeft, float* outputRigh // vst1q_f32(lOut, reg.val[0]); // vst1q_f32(rOut, reg.val[1]); #endif + while (input < sentinel) { *outputLeft++ = *input++; *outputRight++ = *input++; From 50d5c3a80e702c0ccab0b505cfaa4d5a62cb1cef Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Mon, 1 Jun 2020 09:52:17 +0200 Subject: [PATCH 37/42] Brainfart on the ifdef --- src/sfizz/simd/HelpersAVX.cpp | 8 +++---- src/sfizz/simd/HelpersSSE.cpp | 40 +++++++++++++++++------------------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/sfizz/simd/HelpersAVX.cpp b/src/sfizz/simd/HelpersAVX.cpp index 9ca89a65..cad8c2aa 100644 --- a/src/sfizz/simd/HelpersAVX.cpp +++ b/src/sfizz/simd/HelpersAVX.cpp @@ -9,8 +9,8 @@ #include "../MathHelpers.h" #include "Common.h" -#ifdef SFIZZ_HAVE_AVX -#include "immintrin.h" +#if SFIZZ_HAVE_AVX +#include using Type = float; constexpr unsigned TypeAlignment = 8; constexpr unsigned ByteAlignment = TypeAlignment * sizeof(Type); @@ -20,7 +20,7 @@ void applyGainAVX(float gain, const float* input, float* output, unsigned size) { const auto sentinel = output + size; -#ifdef SFIZZ_HAVE_AVX +#if SFIZZ_HAVE_AVX const auto* lastAligned = prevAligned(sentinel); const auto mmGain = _mm256_set1_ps(gain); while (unaligned(input, output) && output < lastAligned) @@ -40,7 +40,7 @@ void applyGainAVX(const float* gain, const float* input, float* output, unsigned { const auto sentinel = output + size; -#ifdef SFIZZ_HAVE_AVX +#if SFIZZ_HAVE_AVX const auto* lastAligned = prevAligned(sentinel); while (unaligned(input, output) && output < lastAligned) *output++ = (*gain++) * (*input++); diff --git a/src/sfizz/simd/HelpersSSE.cpp b/src/sfizz/simd/HelpersSSE.cpp index bacda811..5f51e590 100644 --- a/src/sfizz/simd/HelpersSSE.cpp +++ b/src/sfizz/simd/HelpersSSE.cpp @@ -5,13 +5,13 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "HelpersSSE.h" -#include "../MathHelpers.h" #include "../SIMDConfig.h" +#include "../MathHelpers.h" #include "Common.h" #include -#ifdef SFIZZ_HAVE_SSE -#include "emmintrin.h" +#if SFIZZ_HAVE_SSE2 +#include using Type = float; constexpr unsigned TypeAlignment = 4; constexpr unsigned ByteAlignment = TypeAlignment * sizeof(Type); @@ -21,7 +21,7 @@ void readInterleavedSSE(const float* input, float* outputLeft, float* outputRigh { const auto sentinel = input + inputSize - 1; -#ifdef SFIZZ_HAVE_SSE +#if SFIZZ_HAVE_SSE2 const auto* lastAligned = prevAligned(input + inputSize - TypeAlignment); while (unaligned(input, outputLeft, outputRight) && input < lastAligned) { *outputLeft++ = *input++; @@ -58,7 +58,7 @@ void writeInterleavedSSE(const float* inputLeft, const float* inputRight, float* { const auto sentinel = output + outputSize - 1; -#ifdef SFIZZ_HAVE_SSE +#if SFIZZ_HAVE_SSE2 const auto* lastAligned = prevAligned(output + outputSize - TypeAlignment); while (unaligned(output, inputRight, inputLeft) && output < lastAligned) { *output++ = *inputLeft++; @@ -86,7 +86,7 @@ void applyGainSSE(float gain, const float* input, float* output, unsigned size) { const auto sentinel = output + size; -#ifdef SFIZZ_HAVE_SSE +#if SFIZZ_HAVE_SSE2 const auto* lastAligned = prevAligned(sentinel); const auto mmGain = _mm_set1_ps(gain); while (unaligned(input, output) && output < lastAligned) @@ -106,7 +106,7 @@ void applyGainSSE(const float* gain, const float* input, float* output, unsigned { const auto sentinel = output + size; -#ifdef SFIZZ_HAVE_SSE +#if SFIZZ_HAVE_SSE2 const auto* lastAligned = prevAligned(sentinel); while (unaligned(input, output) && output < lastAligned) *output++ = (*gain++) * (*input++); @@ -143,7 +143,7 @@ void multiplyAddSSE(const float* gain, const float* input, float* output, unsign { const auto sentinel = output + size; -#ifdef SFIZZ_HAVE_SSE +#if SFIZZ_HAVE_SSE2 const auto* lastAligned = prevAligned(sentinel); while (unaligned(input, output) && output < lastAligned) *output++ += (*gain++) * (*input++); @@ -164,7 +164,7 @@ void multiplyAddSSE(float gain, const float* input, float* output, unsigned size { const auto sentinel = output + size; -#ifdef SFIZZ_HAVE_SSE +#if SFIZZ_HAVE_SSE2 const auto* lastAligned = prevAligned(sentinel); while (unaligned(input, output) && output < lastAligned) *output++ += gain * (*input++); @@ -186,7 +186,7 @@ float linearRampSSE(float* output, float start, float step, unsigned size) noexc { const auto sentinel = output + size; -#ifdef SFIZZ_HAVE_SSE +#if SFIZZ_HAVE_SSE2 const auto* lastAligned = prevAligned(sentinel); while (unaligned(output) && output < lastAligned) { *output++ = start; @@ -215,7 +215,7 @@ float multiplicativeRampSSE(float* output, float start, float step, unsigned siz { const auto sentinel = output + size; -#ifdef SFIZZ_HAVE_SSE +#if SFIZZ_HAVE_SSE2 const auto* lastAligned = prevAligned(sentinel); while (unaligned(output) && output < lastAligned) { *output++ = start; @@ -244,7 +244,7 @@ void addSSE(const float* input, float* output, unsigned size) noexcept { const auto sentinel = output + size; -#ifdef SFIZZ_HAVE_SSE +#if SFIZZ_HAVE_SSE2 const auto* lastAligned = prevAligned(sentinel); while (unaligned(input, output) && output < lastAligned) *output++ += *input++; @@ -263,7 +263,7 @@ void addSSE(float value, float* output, unsigned size) noexcept { const auto sentinel = output + size; -#ifdef SFIZZ_HAVE_SSE +#if SFIZZ_HAVE_SSE2 const auto* lastAligned = prevAligned(sentinel); while (unaligned(output) && output < lastAligned) *output++ += value; @@ -283,7 +283,7 @@ void subtractSSE(const float* input, float* output, unsigned size) noexcept { const auto sentinel = output + size; -#ifdef SFIZZ_HAVE_SSE +#if SFIZZ_HAVE_SSE2 const auto* lastAligned = prevAligned(sentinel); while (unaligned(input, output) && output < lastAligned) *output++ -= *input++; @@ -302,7 +302,7 @@ void subtractSSE(float value, float* output, unsigned size) noexcept { const auto sentinel = output + size; -#ifdef SFIZZ_HAVE_SSE +#if SFIZZ_HAVE_SSE2 const auto* lastAligned = prevAligned(sentinel); while (unaligned(output) && output < lastAligned) *output++ -= value; @@ -323,7 +323,7 @@ void copySSE(const float* input, float* output, unsigned size) noexcept // The sentinel is the input here const auto sentinel = input + size; -#ifdef SFIZZ_HAVE_SSE +#if SFIZZ_HAVE_SSE2 const auto* lastAligned = prevAligned(sentinel); while (unaligned(input, output) && input < lastAligned) *output++ = *input++; @@ -345,7 +345,7 @@ float meanSSE(const float* vector, unsigned size) noexcept if (size == 0) return result; -#ifdef SFIZZ_HAVE_SSE +#if SFIZZ_HAVE_SSE2 const auto* lastAligned = prevAligned(sentinel); while (unaligned(vector) && vector < lastAligned) result += *vector++; @@ -377,7 +377,7 @@ float meanSquaredSSE(const float* vector, unsigned size) noexcept if (size == 0) return result; -#ifdef SFIZZ_HAVE_SSE +#if SFIZZ_HAVE_SSE2 const auto* lastAligned = prevAligned(sentinel); while (unaligned(vector) && vector < lastAligned) { result += (*vector) * (*vector); @@ -414,7 +414,7 @@ void cumsumSSE(const float* input, float* output, unsigned size) noexcept const auto sentinel = output + size; *output++ = *input++; -#ifdef SFIZZ_HAVE_SSE +#if SFIZZ_HAVE_SSE2 const auto* lastAligned = prevAligned(sentinel); while (unaligned(input, output) && output < lastAligned) { *output = *(output - 1) + *input; @@ -447,7 +447,7 @@ void diffSSE(const float* input, float* output, unsigned size) noexcept const auto sentinel = output + size; *output++ = *input++; -#ifdef SFIZZ_HAVE_SSE +#if SFIZZ_HAVE_SSE2 const auto* lastAligned = prevAligned(sentinel); while (unaligned(input, output) && output < lastAligned) { *output = *input - *(input - 1); From ca919d65caf11fe0785df126999b8758e99dae4a Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Mon, 1 Jun 2020 10:01:35 +0200 Subject: [PATCH 38/42] Missed a guard --- src/sfizz/simd/HelpersSSE.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sfizz/simd/HelpersSSE.cpp b/src/sfizz/simd/HelpersSSE.cpp index 5f51e590..12fc77a4 100644 --- a/src/sfizz/simd/HelpersSSE.cpp +++ b/src/sfizz/simd/HelpersSSE.cpp @@ -11,7 +11,7 @@ #include #if SFIZZ_HAVE_SSE2 -#include +#include using Type = float; constexpr unsigned TypeAlignment = 4; constexpr unsigned ByteAlignment = TypeAlignment * sizeof(Type); @@ -125,8 +125,8 @@ void divideSSE(const float* input, const float* divisor, float* output, unsigned { const auto sentinel = output + size; +#if SFIZZ_HAVE_SSE2 const auto* lastAligned = prevAligned(sentinel); - while (unaligned(input, output) && output < lastAligned) *output++ = (*input++) / (*divisor++); @@ -134,6 +134,7 @@ void divideSSE(const float* input, const float* divisor, float* output, unsigned _mm_store_ps(output, _mm_div_ps(_mm_load_ps(input), _mm_load_ps(divisor))); incrementAll(divisor, input, output); } +#endif while (output < sentinel) *output++ = (*input++) / (*divisor++); From 75073cf8c0108103d6391fd034e4f8bc12749146 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Mon, 1 Jun 2020 10:38:58 +0200 Subject: [PATCH 39/42] Wrong header in helpersAVX --- src/sfizz/simd/HelpersAVX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfizz/simd/HelpersAVX.cpp b/src/sfizz/simd/HelpersAVX.cpp index cad8c2aa..d9bcd1d7 100644 --- a/src/sfizz/simd/HelpersAVX.cpp +++ b/src/sfizz/simd/HelpersAVX.cpp @@ -5,7 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "HelpersAVX.h" -#include "SIMDConfig.h" +#include "../SIMDConfig.h" #include "../MathHelpers.h" #include "Common.h" From c0fac2cfbbebb041dbaf93f030335d2b1a76f0bc Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 2 Jun 2020 16:04:21 +0200 Subject: [PATCH 40/42] Simplified SIMD dispatch wrappers --- src/sfizz/SIMDHelpers.cpp | 375 ++++++++++++++++++++++----------- src/sfizz/SIMDHelpers.h | 6 + src/sfizz/simd/HelpersScalar.h | 11 +- tests/MainT.cpp | 14 +- 4 files changed, 277 insertions(+), 129 deletions(-) diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index de2e501d..8e02c6e9 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -5,236 +5,361 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "SIMDHelpers.h" -#include -#include "cpuid/cpuinfo.hpp" #include "SIMDConfig.h" +#include "Debug.h" #include "simd/HelpersSSE.h" #include "simd/HelpersAVX.h" +#include "cpuid/cpuinfo.hpp" +#include +#include namespace sfz { -static std::array(SIMDOps::_sentinel)> simdStatus; -static bool simdStatusInitialized = false; -static cpuid::cpuinfo cpuInfo; +template +struct SIMDDispatch { + constexpr SIMDDispatch() = default; -void resetSIMDStatus() + void resetStatus(); + bool getStatus(SIMDOps op) const; + void setStatus(SIMDOps op, bool enable); + + void (*writeInterleaved)(const T* inputLeft, const T* inputRight, T* output, unsigned outputSize) noexcept = &writeInterleavedScalar; + void (*readInterleaved)(const T* input, T* outputLeft, T* outputRight, unsigned inputSize) noexcept = &readInterleavedScalar; + void (*applyGain)(const T* gain, const T* input, T* output, unsigned size) noexcept = &applyGainScalar; + void (*applyGain1)(T gain, const T* input, T* output, unsigned size) noexcept = &applyGainScalar; + void (*divide)(const T* input, const T* divisor, T* output, unsigned size) noexcept = ÷Scalar; + void (*multiplyAdd)(const T* gain, const T* input, T* output, unsigned size) noexcept = &multiplyAddScalar; + void (*multiplyAdd1)(T gain, const T* input, T* output, unsigned size) noexcept = &multiplyAddScalar; + T (*linearRamp)(T* output, T start, T step, unsigned size) noexcept = &linearRampScalar; + T (*multiplicativeRamp)(T* output, T start, T step, unsigned size) noexcept = &multiplicativeRampScalar; + void (*add)(const T* input, T* output, unsigned size) noexcept = &addScalar; + void (*add1)(T value, T* output, unsigned size) noexcept = &addScalar; + void (*subtract)(const T* input, T* output, unsigned size) noexcept = &subtractScalar; + void (*subtract1)(T value, T* output, unsigned size) noexcept = &subtractScalar; + void (*copy)(const T* input, T* output, unsigned size) noexcept = ©Scalar; + void (*cumsum)(const T* input, T* output, unsigned size) noexcept = &cumsumScalar; + void (*diff)(const T* input, T* output, unsigned size) noexcept = &diffScalar; + T (*mean)(const T* vector, unsigned size) noexcept = &meanScalar; + T (*meanSquared)(const T* vector, unsigned size) noexcept = &meanSquaredScalar; + +private: + std::array(SIMDOps::_sentinel)> simdStatus; +}; + +/// + +static SIMDDispatch simdDispatch; + +void resetSIMDOpStatus() { - simdStatus[static_cast(SIMDOps::writeInterleaved)] = false; - simdStatus[static_cast(SIMDOps::readInterleaved)] = false; - simdStatus[static_cast(SIMDOps::fill)] = true; - simdStatus[static_cast(SIMDOps::gain)] = true; - simdStatus[static_cast(SIMDOps::divide)] = false; - simdStatus[static_cast(SIMDOps::linearRamp)] = false; - simdStatus[static_cast(SIMDOps::multiplicativeRamp)] = true; - simdStatus[static_cast(SIMDOps::add)] = false; - simdStatus[static_cast(SIMDOps::subtract)] = false; - simdStatus[static_cast(SIMDOps::multiplyAdd)] = false; - simdStatus[static_cast(SIMDOps::copy)] = false; - simdStatus[static_cast(SIMDOps::cumsum)] = true; - simdStatus[static_cast(SIMDOps::diff)] = false; - simdStatus[static_cast(SIMDOps::sfzInterpolationCast)] = true; - simdStatus[static_cast(SIMDOps::mean)] = false; - simdStatus[static_cast(SIMDOps::meanSquared)] = false; - simdStatus[static_cast(SIMDOps::upsampling)] = true; - simdStatusInitialized = true; + simdDispatch.resetStatus(); } void setSIMDOpStatus(SIMDOps op, bool status) { - if (!simdStatusInitialized) - resetSIMDStatus(); - - simdStatus[static_cast(op)] = status; + simdDispatch.setStatus(op, status); } bool getSIMDOpStatus(SIMDOps op) { - if (!simdStatusInitialized) - resetSIMDStatus(); - - return simdStatus[static_cast(op)]; + return simdDispatch.getStatus(op); } +/// + void readInterleaved(const float* input, float* outputLeft, float* outputRight, unsigned inputSize) noexcept { - if (getSIMDOpStatus(SIMDOps::readInterleaved)) { - if (cpuInfo.has_sse()) - return readInterleavedSSE(input, outputLeft, outputRight, inputSize); - } - return readInterleavedScalar(input, outputLeft, outputRight, inputSize); + return simdDispatch.readInterleaved(input, outputLeft, outputRight, inputSize); } void writeInterleaved(const float* inputLeft, const float* inputRight, float* output, unsigned outputSize) noexcept { - if (getSIMDOpStatus(SIMDOps::writeInterleaved)) { - if (cpuInfo.has_sse()) - return writeInterleavedSSE(inputLeft, inputRight, output, outputSize); - } - return writeInterleavedScalar(inputLeft, inputRight, output, outputSize); + return simdDispatch.writeInterleaved(inputLeft, inputRight, output, outputSize); } template <> void applyGain(float gain, const float* input, float* output, unsigned size) noexcept { - if (getSIMDOpStatus(SIMDOps::gain)) { - if (cpuInfo.has_avx()) - return applyGainAVX(gain, input, output, size); - else if (cpuInfo.has_sse()) - return applyGainSSE(gain, input, output, size); - } - return applyGainScalar(gain, input, output, size); + return simdDispatch.applyGain1(gain, input, output, size); } template <> void applyGain(const float* gain, const float* input, float* output, unsigned size) noexcept { - if (getSIMDOpStatus(SIMDOps::gain)) { - if (cpuInfo.has_avx()) - return applyGainAVX(gain, input, output, size); - else if (cpuInfo.has_sse()) - return applyGainSSE(gain, input, output, size); - } - return applyGainScalar(gain, input, output, size); + return simdDispatch.applyGain(gain, input, output, size); } template <> void divide(const float* input, const float* divisor, float* output, unsigned size) noexcept { - if (getSIMDOpStatus(SIMDOps::divide)) { - if (cpuInfo.has_sse()) - return divideSSE(input, divisor, output, size); - } - return divideScalar(input, divisor, output, size); + return simdDispatch.divide(input, divisor, output, size); } template <> void multiplyAdd(const float* gain, const float* input, float* output, unsigned size) noexcept { - if (getSIMDOpStatus(SIMDOps::multiplyAdd)) { - if (cpuInfo.has_sse()) - return multiplyAddSSE(gain, input, output, size); - } - return multiplyAddScalar(gain, input, output, size); + return simdDispatch.multiplyAdd(gain, input, output, size); } template <> void multiplyAdd(float gain, const float* input, float* output, unsigned size) noexcept { - if (getSIMDOpStatus(SIMDOps::multiplyAdd)) { - if (cpuInfo.has_sse()) - return multiplyAddSSE(gain, input, output, size); - } - return multiplyAddScalar(gain, input, output, size); + return simdDispatch.multiplyAdd1(gain, input, output, size); } template <> float linearRamp(float* output, float start, float step, unsigned size) noexcept { - if (getSIMDOpStatus(SIMDOps::linearRamp)) { - if (cpuInfo.has_sse()) - return linearRampSSE(output, start, step, size); - } - return linearRampScalar(output, start, step, size); + return simdDispatch.linearRamp(output, start, step, size); } template <> float multiplicativeRamp(float* output, float start, float step, unsigned size) noexcept { - if (getSIMDOpStatus(SIMDOps::multiplicativeRamp)) { - if (cpuInfo.has_sse()) - return multiplicativeRampSSE(output, start, step, size); - } - return multiplicativeRampScalar(output, start, step, size); + return simdDispatch.multiplicativeRamp(output, start, step, size); } template <> void add(const float* input, float* output, unsigned size) noexcept { - if (getSIMDOpStatus(SIMDOps::add)) { - if (cpuInfo.has_sse()) - return addSSE(input, output, size); - } - return addScalar(input, output, size); + return simdDispatch.add(input, output, size); } template <> void add(float value, float* output, unsigned size) noexcept { - if (getSIMDOpStatus(SIMDOps::add)) { - if (cpuInfo.has_sse()) - return addSSE(value, output, size); - } - return addScalar(value, output, size); + return simdDispatch.add1(value, output, size); } template <> void subtract(const float* input, float* output, unsigned size) noexcept { - if (getSIMDOpStatus(SIMDOps::subtract)) { - if (cpuInfo.has_sse()) - return subtractSSE(input, output, size); - } - return subtractScalar(input, output, size); + return simdDispatch.subtract(input, output, size); } template <> void subtract(float value, float* output, unsigned size) noexcept { - if (getSIMDOpStatus(SIMDOps::subtract)) { - if (cpuInfo.has_sse()) - return subtractSSE(value, output, size); - } - return subtractScalar(value, output, size); + return simdDispatch.subtract1(value, output, size); } template <> void copy(const float* input, float* output, unsigned size) noexcept { - if (getSIMDOpStatus(SIMDOps::copy)) { - if (cpuInfo.has_sse()) - return copySSE(input, output, size); - } - std::copy(input, input + size, output); + return simdDispatch.copy(input, output, size); } template <> float mean(const float* vector, unsigned size) noexcept { - if (getSIMDOpStatus(SIMDOps::mean)) { - if (cpuInfo.has_sse()) - return meanSSE(vector, size); - } - return meanScalar(vector, size); + return simdDispatch.mean(vector, size); } template <> float meanSquared(const float* vector, unsigned size) noexcept { - if (getSIMDOpStatus(SIMDOps::meanSquared)) { - if (cpuInfo.has_sse()) - return meanSquaredSSE(vector, size); - } - return meanSquaredScalar(vector, size); + return simdDispatch.meanSquared(vector, size); } template <> void cumsum(const float* input, float* output, unsigned size) noexcept { - if (getSIMDOpStatus(SIMDOps::cumsum)) { - if (cpuInfo.has_sse()) - return cumsumSSE(input, output, size); - } - return cumsumScalar(input, output, size); + return simdDispatch.cumsum(input, output, size); } template <> void diff(const float* input, float* output, unsigned size) noexcept { - if (getSIMDOpStatus(SIMDOps::diff)) { - if (cpuInfo.has_sse()) - return diffSSE(input, output, size); + return simdDispatch.diff(input, output, size); +} + +/// + +static cpuid::cpuinfo& cpuInfo() +{ + static cpuid::cpuinfo info; + return info; +} + +template +bool SIMDDispatch::getStatus(SIMDOps op) const +{ + const unsigned index = static_cast(op); + ASSERT(index < simdStatus.size()); + return simdStatus[index]; +} + +template +void SIMDDispatch::setStatus(SIMDOps op, bool enable) +{ + const unsigned index = static_cast(op); + ASSERT(index < simdStatus.size()); + + simdStatus[index] = enable; + + const cpuid::cpuinfo& info = cpuInfo(); + bool useSSE = enable && info.has_sse(); + bool useAVX = enable && info.has_avx(); + + switch (op) { + default: + break; + + case SIMDOps::writeInterleaved: + if (useSSE) + writeInterleaved = &writeInterleavedSSE; + else + writeInterleaved = &writeInterleavedScalar; + break; + + case SIMDOps::readInterleaved: + if (useSSE) + readInterleaved = &readInterleavedSSE; + else + readInterleaved = &readInterleavedScalar; + break; + + case SIMDOps::gain: + if (useAVX) { + applyGain = &applyGainAVX; + applyGain1 = &applyGainAVX; + } + else if (useSSE) { + applyGain = &applyGainSSE; + applyGain1 = &applyGainSSE; + } + else { + applyGain = &applyGainScalar; + applyGain1 = &applyGainScalar; + } + break; + + case SIMDOps::divide: + if (useSSE) + divide = ÷SSE; + else + divide = ÷Scalar; + break; + + case SIMDOps::multiplyAdd: + if (useSSE) { + multiplyAdd = &multiplyAddSSE; + multiplyAdd1 = &multiplyAddSSE; + } + else { + multiplyAdd = &multiplyAddScalar; + multiplyAdd1 = &multiplyAddScalar; + } + break; + + case SIMDOps::linearRamp: + if (useSSE) + linearRamp = &linearRampSSE; + else + linearRamp = &linearRampScalar; + break; + + case SIMDOps::multiplicativeRamp: + if (useSSE) + multiplicativeRamp = &multiplicativeRampSSE; + else + multiplicativeRamp = &multiplicativeRampScalar; + break; + + case SIMDOps::add: + if (useSSE) { + add = &addSSE; + add1 = &addSSE; + } + else { + add = &addScalar; + add1 = &addScalar; + } + break; + + case SIMDOps::subtract: + if (useSSE) { + subtract = &subtractSSE; + subtract1 = &subtractSSE; + } + else { + subtract = &subtractScalar; + subtract1 = &subtractScalar; + } + break; + + case SIMDOps::copy: + if (useSSE) + copy = ©SSE; + else + copy = ©Scalar; + break; + + case SIMDOps::cumsum: + if (useSSE) + cumsum = &cumsumSSE; + else + cumsum = &cumsumScalar; + break; + + case SIMDOps::diff: + if (useSSE) + diff = &diffSSE; + else + diff = &diffScalar; + break; + + case SIMDOps::mean: + if (useSSE) + mean = &meanSSE; + else + mean = &meanScalar; + break; + + case SIMDOps::meanSquared: + if (useSSE) + meanSquared = &meanSquaredSSE; + else + meanSquared = &meanSquaredScalar; + break; + } +} + +template +void SIMDDispatch::resetStatus() +{ + setStatus(SIMDOps::writeInterleaved, false); + setStatus(SIMDOps::readInterleaved, false); + setStatus(SIMDOps::fill, true); + setStatus(SIMDOps::gain, true); + setStatus(SIMDOps::divide, false); + setStatus(SIMDOps::linearRamp, false); + setStatus(SIMDOps::multiplicativeRamp, true); + setStatus(SIMDOps::add, false); + setStatus(SIMDOps::subtract, false); + setStatus(SIMDOps::multiplyAdd, false); + setStatus(SIMDOps::copy, false); + setStatus(SIMDOps::cumsum, true); + setStatus(SIMDOps::diff, false); + setStatus(SIMDOps::sfzInterpolationCast, true); + setStatus(SIMDOps::mean, false); + setStatus(SIMDOps::meanSquared, false); + setStatus(SIMDOps::upsampling, true); +} + +/// + +static volatile bool simdInitialized = false; +static std::mutex simdMutex; + +SIMDInitializer::SIMDInitializer() +{ + std::lock_guard lock { simdMutex }; + + if (!simdInitialized) { + simdDispatch.resetStatus(); + simdInitialized = true; } - return diffScalar(input, output, size); } } diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index 9e3bd06b..7379875d 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -59,9 +59,15 @@ enum class SIMDOps { }; // Enable or disable SIMD accelerators at runtime +void resetSIMDOpStatus(); void setSIMDOpStatus(SIMDOps op, bool status); bool getSIMDOpStatus(SIMDOps op); +// Initializer object which ensures to prepare SIMD dispatch +struct SIMDInitializer { + SIMDInitializer(); +}; + /** * @brief Read interleaved stereo data from a buffer and separate it in a left/right pair of buffers. * diff --git a/src/sfizz/simd/HelpersScalar.h b/src/sfizz/simd/HelpersScalar.h index 1554e636..d24b75ea 100644 --- a/src/sfizz/simd/HelpersScalar.h +++ b/src/sfizz/simd/HelpersScalar.h @@ -5,9 +5,10 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once +#include template -inline void readInterleavedScalar(const T* input, T* outputLeft, T* outputRight, unsigned inputSize) +inline void readInterleavedScalar(const T* input, T* outputLeft, T* outputRight, unsigned inputSize) noexcept { const auto sentinel = input + inputSize - 1; while (input < sentinel) { @@ -17,7 +18,7 @@ inline void readInterleavedScalar(const T* input, T* outputLeft, T* outputRight, } template -inline void writeInterleavedScalar(const T* inputLeft, const T* inputRight, T* output, unsigned outputSize) +inline void writeInterleavedScalar(const T* inputLeft, const T* inputRight, T* output, unsigned outputSize) noexcept { const auto sentinel = output + outputSize - 1; while (output < sentinel) { @@ -120,6 +121,12 @@ inline void subtractScalar(T value, T* output, unsigned size) noexcept *output++ -= value; } +template +void copyScalar(const T* input, T* output, unsigned size) noexcept +{ + std::copy(input, input + size, output); +} + template T meanScalar(const T* vector, unsigned size) noexcept { diff --git a/tests/MainT.cpp b/tests/MainT.cpp index ba9cc3b4..40865cab 100644 --- a/tests/MainT.cpp +++ b/tests/MainT.cpp @@ -1,2 +1,12 @@ -#define CATCH_CONFIG_MAIN -#include "catch2/catch.hpp" \ No newline at end of file +#include "sfizz/SIMDHelpers.h" + +#define CATCH_CONFIG_RUNNER +#include "catch2/catch.hpp" + +int main(int argc, char* argv[]) +{ + sfz::SIMDInitializer simdInit; + + int result = Catch::Session().run(argc, argv); + return result; +} From da9e503657f5cfb05182ff2da943ba41f1cbf1f2 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Wed, 3 Jun 2020 21:57:04 +0200 Subject: [PATCH 41/42] Use a dispatching object rather than branchesUpdate the benchmarksRemove the SIMDInitializerInfer type for simd helpers --- benchmarks/BM_add.cpp | 24 +- benchmarks/BM_copy.cpp | 8 +- benchmarks/BM_cumsum.cpp | 8 +- benchmarks/BM_diff.cpp | 8 +- benchmarks/BM_divide.cpp | 8 +- benchmarks/BM_gain.cpp | 16 +- benchmarks/BM_mean.cpp | 8 +- benchmarks/BM_meanSquared.cpp | 8 +- benchmarks/BM_multiplyAdd.cpp | 8 +- benchmarks/BM_multiplyAddFixedGain.cpp | 16 +- benchmarks/BM_ramp.cpp | 16 +- benchmarks/BM_readInterleaved.cpp | 12 +- benchmarks/BM_subtract.cpp | 8 +- benchmarks/BM_writeInterleaved.cpp | 12 +- scripts/run_clang_tidy.sh | 3 +- src/sfizz/AudioSpan.h | 2 +- src/sfizz/Debug.h | 4 +- src/sfizz/Effects.cpp | 6 +- src/sfizz/MathHelpers.h | 2 +- src/sfizz/SIMDHelpers.cpp | 526 +++++++++++-------------- src/sfizz/SIMDHelpers.h | 87 ++-- src/sfizz/Synth.cpp | 13 +- src/sfizz/Voice.cpp | 24 +- src/sfizz/effects/Strings.cpp | 4 +- src/sfizz/simd/HelpersAVX.cpp | 4 +- src/sfizz/simd/HelpersAVX.h | 4 +- src/sfizz/simd/HelpersSSE.cpp | 10 +- src/sfizz/simd/HelpersSSE.h | 10 +- src/sfizz/simd/HelpersScalar.h | 10 +- tests/MainT.cpp | 2 - tests/SIMDHelpersT.cpp | 168 ++++---- 31 files changed, 498 insertions(+), 541 deletions(-) diff --git a/benchmarks/BM_add.cpp b/benchmarks/BM_add.cpp index 5e2d278e..85277c1c 100644 --- a/benchmarks/BM_add.cpp +++ b/benchmarks/BM_add.cpp @@ -36,39 +36,39 @@ public: BENCHMARK_DEFINE_F(AddArray, Value_Scalar)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::add, false); - sfz::add(1.1f, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::add1, false); + sfz::add1(1.1f, absl::MakeSpan(output)); } } BENCHMARK_DEFINE_F(AddArray, Value_SIMD)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::add, true); - sfz::add(1.1f, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::add1, true); + sfz::add1(1.1f, absl::MakeSpan(output)); } } BENCHMARK_DEFINE_F(AddArray, Value_Scalar_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::add, false); - sfz::add(1.1f, absl::MakeSpan(output).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::add1, false); + sfz::add1(1.1f, absl::MakeSpan(output).subspan(1)); } } BENCHMARK_DEFINE_F(AddArray, Value_SIMD_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::add, true); - sfz::add(1.1f, absl::MakeSpan(output).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::add1, true); + sfz::add1(1.1f, absl::MakeSpan(output).subspan(1)); } } BENCHMARK_DEFINE_F(AddArray, Scalar)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::add, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::add, false); sfz::add(input, absl::MakeSpan(output)); } } @@ -76,7 +76,7 @@ BENCHMARK_DEFINE_F(AddArray, Scalar)(benchmark::State& state) { BENCHMARK_DEFINE_F(AddArray, SIMD)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::add, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::add, true); sfz::add(input, absl::MakeSpan(output)); } } @@ -84,7 +84,7 @@ BENCHMARK_DEFINE_F(AddArray, SIMD)(benchmark::State& state) { BENCHMARK_DEFINE_F(AddArray, Scalar_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::add, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::add, false); sfz::add(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } @@ -92,7 +92,7 @@ BENCHMARK_DEFINE_F(AddArray, Scalar_Unaligned)(benchmark::State& state) { BENCHMARK_DEFINE_F(AddArray, SIMD_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::add, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::add, true); sfz::add(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } diff --git a/benchmarks/BM_copy.cpp b/benchmarks/BM_copy.cpp index 1196730b..4f371b8a 100644 --- a/benchmarks/BM_copy.cpp +++ b/benchmarks/BM_copy.cpp @@ -43,7 +43,7 @@ BENCHMARK_DEFINE_F(CopyArray, StdCopy)(benchmark::State& state) { BENCHMARK_DEFINE_F(CopyArray, Scalar)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::copy, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::copy, false); sfz::copy(input, absl::MakeSpan(output)); } } @@ -51,7 +51,7 @@ BENCHMARK_DEFINE_F(CopyArray, Scalar)(benchmark::State& state) { BENCHMARK_DEFINE_F(CopyArray, SIMD)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::copy, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::copy, true); sfz::copy(input, absl::MakeSpan(output)); } } @@ -66,7 +66,7 @@ BENCHMARK_DEFINE_F(CopyArray, StdCopy_Unaligned)(benchmark::State& state) { BENCHMARK_DEFINE_F(CopyArray, Scalar_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::copy, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::copy, false); sfz::copy(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } @@ -74,7 +74,7 @@ BENCHMARK_DEFINE_F(CopyArray, Scalar_Unaligned)(benchmark::State& state) { BENCHMARK_DEFINE_F(CopyArray, SIMD_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::copy, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::copy, true); sfz::copy(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } diff --git a/benchmarks/BM_cumsum.cpp b/benchmarks/BM_cumsum.cpp index 9df02b76..a30d14d2 100644 --- a/benchmarks/BM_cumsum.cpp +++ b/benchmarks/BM_cumsum.cpp @@ -35,7 +35,7 @@ public: BENCHMARK_DEFINE_F(CumArray, Sum_Scalar)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, false); sfz::cumsum(input, absl::MakeSpan(output)); } } @@ -43,7 +43,7 @@ BENCHMARK_DEFINE_F(CumArray, Sum_Scalar)(benchmark::State& state) { BENCHMARK_DEFINE_F(CumArray, Sum_SIMD)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, true); sfz::cumsum(input, absl::MakeSpan(output)); } } @@ -51,7 +51,7 @@ BENCHMARK_DEFINE_F(CumArray, Sum_SIMD)(benchmark::State& state) { BENCHMARK_DEFINE_F(CumArray, Sum_Scalar_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, false); sfz::cumsum(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } @@ -59,7 +59,7 @@ BENCHMARK_DEFINE_F(CumArray, Sum_Scalar_Unaligned)(benchmark::State& state) { BENCHMARK_DEFINE_F(CumArray, Sum_SIMD_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, true); sfz::cumsum(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } diff --git a/benchmarks/BM_diff.cpp b/benchmarks/BM_diff.cpp index 2d2271bd..c0fd4924 100644 --- a/benchmarks/BM_diff.cpp +++ b/benchmarks/BM_diff.cpp @@ -37,7 +37,7 @@ public: BENCHMARK_DEFINE_F(DiffArray, Diff_Scalar)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::diff, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::diff, false); sfz::diff(input, absl::MakeSpan(output)); } } @@ -45,7 +45,7 @@ BENCHMARK_DEFINE_F(DiffArray, Diff_Scalar)(benchmark::State& state) { BENCHMARK_DEFINE_F(DiffArray, Diff_SIMD)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::diff, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::diff, true); sfz::diff(input, absl::MakeSpan(output)); } } @@ -53,7 +53,7 @@ BENCHMARK_DEFINE_F(DiffArray, Diff_SIMD)(benchmark::State& state) { BENCHMARK_DEFINE_F(DiffArray, Diff_Scalar_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::diff, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::diff, false); sfz::diff(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } @@ -61,7 +61,7 @@ BENCHMARK_DEFINE_F(DiffArray, Diff_Scalar_Unaligned)(benchmark::State& state) { BENCHMARK_DEFINE_F(DiffArray, Diff_SIMD_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::diff, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::diff, true); sfz::diff(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } diff --git a/benchmarks/BM_divide.cpp b/benchmarks/BM_divide.cpp index 48f5064e..b3580439 100644 --- a/benchmarks/BM_divide.cpp +++ b/benchmarks/BM_divide.cpp @@ -46,7 +46,7 @@ BENCHMARK_DEFINE_F(Divide, Straight)(benchmark::State& state) { BENCHMARK_DEFINE_F(Divide, Scalar)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::divide, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::divide, false); sfz::divide(input, divisor, absl::MakeSpan(output)); } } @@ -54,7 +54,7 @@ BENCHMARK_DEFINE_F(Divide, Scalar)(benchmark::State& state) { BENCHMARK_DEFINE_F(Divide, SIMD)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::divide, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::divide, true); sfz::divide(input, divisor, absl::MakeSpan(output)); } } @@ -62,7 +62,7 @@ BENCHMARK_DEFINE_F(Divide, SIMD)(benchmark::State& state) { BENCHMARK_DEFINE_F(Divide, Scalar_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::divide, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::divide, false); sfz::divide(absl::MakeSpan(input).subspan(1), absl::MakeSpan(divisor).subspan(1), absl::MakeSpan(output).subspan(1)); } } @@ -70,7 +70,7 @@ BENCHMARK_DEFINE_F(Divide, Scalar_Unaligned)(benchmark::State& state) { BENCHMARK_DEFINE_F(Divide, SIMD_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::divide, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::divide, true); sfz::divide(absl::MakeSpan(input).subspan(1), absl::MakeSpan(divisor).subspan(1), absl::MakeSpan(output).subspan(1)); } } diff --git a/benchmarks/BM_gain.cpp b/benchmarks/BM_gain.cpp index cd2096d7..d47ae719 100644 --- a/benchmarks/BM_gain.cpp +++ b/benchmarks/BM_gain.cpp @@ -66,16 +66,16 @@ BENCHMARK_DEFINE_F(GainSingle, Straight)(benchmark::State& state) { BENCHMARK_DEFINE_F(GainSingle, Scalar)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); - sfz::applyGain(gain, input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain1, false); + sfz::applyGain1(gain, input, absl::MakeSpan(output)); } } BENCHMARK_DEFINE_F(GainSingle, SIMD)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); - sfz::applyGain(gain, input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain1, true); + sfz::applyGain1(gain, input, absl::MakeSpan(output)); } } @@ -90,7 +90,7 @@ BENCHMARK_DEFINE_F(GainArray, Straight)(benchmark::State& state) { BENCHMARK_DEFINE_F(GainArray, Scalar)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); sfz::applyGain(gain, input, absl::MakeSpan(output)); } } @@ -98,7 +98,7 @@ BENCHMARK_DEFINE_F(GainArray, Scalar)(benchmark::State& state) { BENCHMARK_DEFINE_F(GainArray, SIMD)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); sfz::applyGain(gain, input, absl::MakeSpan(output)); } } @@ -106,7 +106,7 @@ BENCHMARK_DEFINE_F(GainArray, SIMD)(benchmark::State& state) { BENCHMARK_DEFINE_F(GainArray, Scalar_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); sfz::applyGain(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } @@ -114,7 +114,7 @@ BENCHMARK_DEFINE_F(GainArray, Scalar_Unaligned)(benchmark::State& state) { BENCHMARK_DEFINE_F(GainArray, SIMD_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); sfz::applyGain(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } diff --git a/benchmarks/BM_mean.cpp b/benchmarks/BM_mean.cpp index 88d50624..7ac9e59c 100644 --- a/benchmarks/BM_mean.cpp +++ b/benchmarks/BM_mean.cpp @@ -34,7 +34,7 @@ BENCHMARK_DEFINE_F(MeanArray, Scalar) (benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false); auto result = sfz::mean(input); benchmark::DoNotOptimize(result); } @@ -44,7 +44,7 @@ BENCHMARK_DEFINE_F(MeanArray, SIMD) (benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true); auto result = sfz::mean(input); benchmark::DoNotOptimize(result); } @@ -54,7 +54,7 @@ BENCHMARK_DEFINE_F(MeanArray, Scalar_Unaligned) (benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false); auto result = sfz::mean(absl::MakeSpan(input).subspan(1)); benchmark::DoNotOptimize(result); } @@ -64,7 +64,7 @@ BENCHMARK_DEFINE_F(MeanArray, SIMD_Unaligned) (benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true); auto result = sfz::mean(absl::MakeSpan(input).subspan(1)); benchmark::DoNotOptimize(result); } diff --git a/benchmarks/BM_meanSquared.cpp b/benchmarks/BM_meanSquared.cpp index ec8c1f5c..0b1c159e 100644 --- a/benchmarks/BM_meanSquared.cpp +++ b/benchmarks/BM_meanSquared.cpp @@ -34,7 +34,7 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, Scalar) (benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); auto result = sfz::meanSquared(input); benchmark::DoNotOptimize(result); } @@ -44,7 +44,7 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, SIMD) (benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); auto result = sfz::meanSquared(input); benchmark::DoNotOptimize(result); } @@ -54,7 +54,7 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, Scalar_Unaligned) (benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); auto result = sfz::meanSquared(absl::MakeSpan(input).subspan(1)); benchmark::DoNotOptimize(result); } @@ -64,7 +64,7 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, SIMD_Unaligned) (benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); auto result = sfz::meanSquared(absl::MakeSpan(input).subspan(1)); benchmark::DoNotOptimize(result); } diff --git a/benchmarks/BM_multiplyAdd.cpp b/benchmarks/BM_multiplyAdd.cpp index a85e28ab..d4da2b36 100644 --- a/benchmarks/BM_multiplyAdd.cpp +++ b/benchmarks/BM_multiplyAdd.cpp @@ -46,7 +46,7 @@ BENCHMARK_DEFINE_F(MultiplyAdd, Straight)(benchmark::State& state) { BENCHMARK_DEFINE_F(MultiplyAdd, Scalar)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); } } @@ -54,7 +54,7 @@ BENCHMARK_DEFINE_F(MultiplyAdd, Scalar)(benchmark::State& state) { BENCHMARK_DEFINE_F(MultiplyAdd, SIMD)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); } } @@ -62,7 +62,7 @@ BENCHMARK_DEFINE_F(MultiplyAdd, SIMD)(benchmark::State& state) { BENCHMARK_DEFINE_F(MultiplyAdd, Scalar_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); sfz::multiplyAdd(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } @@ -70,7 +70,7 @@ BENCHMARK_DEFINE_F(MultiplyAdd, Scalar_Unaligned)(benchmark::State& state) { BENCHMARK_DEFINE_F(MultiplyAdd, SIMD_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); sfz::multiplyAdd(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } diff --git a/benchmarks/BM_multiplyAddFixedGain.cpp b/benchmarks/BM_multiplyAddFixedGain.cpp index 97a4001a..7bbd4595 100644 --- a/benchmarks/BM_multiplyAddFixedGain.cpp +++ b/benchmarks/BM_multiplyAddFixedGain.cpp @@ -48,8 +48,8 @@ BENCHMARK_DEFINE_F(MultiplyAddFixedGain, Scalar) (benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); - sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd1, false); + sfz::multiplyAdd1(gain, input, absl::MakeSpan(output)); } } @@ -57,8 +57,8 @@ BENCHMARK_DEFINE_F(MultiplyAddFixedGain, SIMD) (benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); - sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd1, true); + sfz::multiplyAdd1(gain, input, absl::MakeSpan(output)); } } @@ -66,8 +66,8 @@ BENCHMARK_DEFINE_F(MultiplyAddFixedGain, Scalar_Unaligned) (benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); - sfz::multiplyAdd(gain, absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd1, false); + sfz::multiplyAdd1(gain, absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } @@ -75,8 +75,8 @@ BENCHMARK_DEFINE_F(MultiplyAddFixedGain, SIMD_Unaligned) (benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); - sfz::multiplyAdd(gain, absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd1, true); + sfz::multiplyAdd1(gain, absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } diff --git a/benchmarks/BM_ramp.cpp b/benchmarks/BM_ramp.cpp index ef2b5379..b5a5209f 100644 --- a/benchmarks/BM_ramp.cpp +++ b/benchmarks/BM_ramp.cpp @@ -30,7 +30,7 @@ static void LinearScalar(benchmark::State& state) { for (auto _ : state) { auto value = dist(gen); - sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, false); sfz::linearRamp(absl::MakeSpan(output), 0.0f, value); } } @@ -43,7 +43,7 @@ static void LinearSIMD(benchmark::State& state) { for (auto _ : state) { auto value = dist(gen); - sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); sfz::linearRamp(absl::MakeSpan(output), 0.0f, value); } } @@ -55,7 +55,7 @@ static void LinearScalarUnaligned(benchmark::State& state) { for (auto _ : state) { auto value = dist(gen); - sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, false); sfz::linearRamp(absl::MakeSpan(output).subspan(1), 0.0f, value); } } @@ -68,7 +68,7 @@ static void LinearSIMDUnaligned(benchmark::State& state) { for (auto _ : state) { auto value = dist(gen); - sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); sfz::linearRamp(absl::MakeSpan(output).subspan(1), 0.0f, value); } } @@ -81,7 +81,7 @@ static void MulScalar(benchmark::State& state) { for (auto _ : state) { auto value = dist(gen); - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, false); sfz::multiplicativeRamp(absl::MakeSpan(output), 1.0f, value); } } @@ -94,7 +94,7 @@ static void MulSIMD(benchmark::State& state) { for (auto _ : state) { auto value = dist(gen); - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, true); sfz::multiplicativeRamp(absl::MakeSpan(output), 1.0f, value); } } @@ -106,7 +106,7 @@ static void MulScalarUnaligned(benchmark::State& state) { for (auto _ : state) { auto value = dist(gen); - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, false); sfz::multiplicativeRamp(absl::MakeSpan(output).subspan(1), 1.0f, value); } } @@ -119,7 +119,7 @@ static void MulSIMDUnaligned(benchmark::State& state) { for (auto _ : state) { auto value = dist(gen); - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, true); sfz::multiplicativeRamp(absl::MakeSpan(output).subspan(1), 1.0f, value); } } diff --git a/benchmarks/BM_readInterleaved.cpp b/benchmarks/BM_readInterleaved.cpp index 2255e98f..5d91b888 100644 --- a/benchmarks/BM_readInterleaved.cpp +++ b/benchmarks/BM_readInterleaved.cpp @@ -18,7 +18,7 @@ static void Scalar(benchmark::State& state) { std::iota(input.begin(), input.end(), 1.0f); for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); sfz::readInterleaved(input, absl::MakeSpan(outputLeft), absl::MakeSpan(outputRight)); } } @@ -30,7 +30,7 @@ static void SSE(benchmark::State& state) { std::iota(input.begin(), input.end(), 1.0f); for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); sfz::readInterleaved(input, absl::MakeSpan(outputLeft), absl::MakeSpan(outputRight)); } } @@ -41,7 +41,7 @@ static void Scalar_Unaligned(benchmark::State& state) { sfz::Buffer outputRight (state.range(0)); std::iota(input.begin(), input.end(), 1.0f); for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); sfz::readInterleaved( absl::MakeSpan(input).subspan(2), absl::MakeSpan(outputLeft), @@ -56,7 +56,7 @@ static void SSE_Unaligned(benchmark::State& state) { sfz::Buffer outputRight (state.range(0)); std::iota(input.begin(), input.end(), 1.0f); for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); sfz::readInterleaved( absl::MakeSpan(input).subspan(2), absl::MakeSpan(outputLeft), @@ -71,7 +71,7 @@ static void Scalar_Unaligned_2(benchmark::State& state) { sfz::Buffer outputRight (state.range(0)); std::iota(input.begin(), input.end(), 1.0f); for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); sfz::readInterleaved( absl::MakeSpan(input).subspan(2), absl::MakeSpan(outputLeft).subspan(1), @@ -86,7 +86,7 @@ static void SSE_Unaligned_2(benchmark::State& state) { sfz::Buffer outputRight (state.range(0)); std::iota(input.begin(), input.end(), 1.0f); for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); sfz::readInterleaved( absl::MakeSpan(input).subspan(2), absl::MakeSpan(outputLeft).subspan(1), diff --git a/benchmarks/BM_subtract.cpp b/benchmarks/BM_subtract.cpp index 0bc60f15..e500d9e9 100644 --- a/benchmarks/BM_subtract.cpp +++ b/benchmarks/BM_subtract.cpp @@ -36,7 +36,7 @@ public: BENCHMARK_DEFINE_F(SubArray, Scalar)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, false); sfz::subtract(input, absl::MakeSpan(output)); } } @@ -44,7 +44,7 @@ BENCHMARK_DEFINE_F(SubArray, Scalar)(benchmark::State& state) { BENCHMARK_DEFINE_F(SubArray, SIMD)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, true); sfz::subtract(input, absl::MakeSpan(output)); } } @@ -52,7 +52,7 @@ BENCHMARK_DEFINE_F(SubArray, SIMD)(benchmark::State& state) { BENCHMARK_DEFINE_F(SubArray, Scalar_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, false); sfz::subtract(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } @@ -60,7 +60,7 @@ BENCHMARK_DEFINE_F(SubArray, Scalar_Unaligned)(benchmark::State& state) { BENCHMARK_DEFINE_F(SubArray, SIMD_Unaligned)(benchmark::State& state) { for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, true); sfz::subtract(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1)); } } diff --git a/benchmarks/BM_writeInterleaved.cpp b/benchmarks/BM_writeInterleaved.cpp index f7612fa9..7313adb7 100644 --- a/benchmarks/BM_writeInterleaved.cpp +++ b/benchmarks/BM_writeInterleaved.cpp @@ -19,7 +19,7 @@ static void Interleaved_Write(benchmark::State& state) { std::iota(inputRight.begin(), inputRight.end(), 1.0f); for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); sfz::writeInterleaved(inputLeft, inputRight, absl::MakeSpan(output)); } } @@ -31,7 +31,7 @@ static void Interleaved_Write_SSE(benchmark::State& state) { std::iota(inputLeft.begin(), inputLeft.end(), 1.0f); std::iota(inputRight.begin(), inputRight.end(), 1.0f); for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true); sfz::writeInterleaved(inputLeft, inputRight, absl::MakeSpan(output)); } } @@ -43,7 +43,7 @@ static void Unaligned_Interleaved_Write(benchmark::State& state) { std::iota(inputLeft.begin(), inputLeft.end(), 1.0f); std::iota(inputRight.begin(), inputRight.end(), 1.0f); for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); sfz::writeInterleaved( absl::MakeSpan(inputLeft).subspan(1), absl::MakeSpan(inputRight).subspan(1), @@ -59,7 +59,7 @@ static void Unaligned_Interleaved_Write_SSE(benchmark::State& state) { std::iota(inputLeft.begin(), inputLeft.end(), 1.0f); std::iota(inputRight.begin(), inputRight.end(), 1.0f); for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true); sfz::writeInterleaved( absl::MakeSpan(inputLeft).subspan(1), absl::MakeSpan(inputRight).subspan(1), @@ -75,7 +75,7 @@ static void Unaligned_Interleaved_Write_2(benchmark::State& state) { std::iota(inputLeft.begin(), inputLeft.end(), 1.0f); std::iota(inputRight.begin(), inputRight.end(), 1.0f); for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); sfz::writeInterleaved( absl::MakeSpan(inputLeft), absl::MakeSpan(inputRight).subspan(1), @@ -91,7 +91,7 @@ static void Unaligned_Interleaved_Write_SSE_2(benchmark::State& state) { std::iota(inputLeft.begin(), inputLeft.end(), 1.0f); std::iota(inputRight.begin(), inputRight.end(), 1.0f); for (auto _ : state) { - sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true); sfz::writeInterleaved( absl::MakeSpan(inputLeft), absl::MakeSpan(inputRight).subspan(1), diff --git a/scripts/run_clang_tidy.sh b/scripts/run_clang_tidy.sh index 83998476..a25f69f9 100755 --- a/scripts/run_clang_tidy.sh +++ b/scripts/run_clang_tidy.sh @@ -32,4 +32,5 @@ clang-tidy \ vst/SfizzVstState.cpp \ -- -Iexternal/abseil-cpp -Isrc/external -Isrc/external/pugixml/src \ -Isrc/sfizz -Isrc -Isrc/external/spline -Isrc/external/cpuid/src \ - -Ivst -Ivst/external/VST_SDK/VST3_SDK -Ivst/external/VST_SDK/VST3_SDK/vstgui4 -Ivst/external/ring_buffer -DNDEBUG + -Ivst -Ivst/external/VST_SDK/VST3_SDK -Ivst/external/VST_SDK/VST3_SDK/vstgui4 -Ivst/external/ring_buffer \ + -DNDEBUG -std=c++17 diff --git a/src/sfizz/AudioSpan.h b/src/sfizz/AudioSpan.h index 21fcb4be..0791eafa 100644 --- a/src/sfizz/AudioSpan.h +++ b/src/sfizz/AudioSpan.h @@ -303,7 +303,7 @@ public: { static_assert(!std::is_const::value, "Can't allow mutating operations on const AudioSpans"); for (size_t i = 0; i < numChannels; ++i) - sfz::applyGain(gain, getSpan(i)); + sfz::applyGain1(gain, getSpan(i)); } /** diff --git a/src/sfizz/Debug.h b/src/sfizz/Debug.h index c7020a9d..2c2f270c 100644 --- a/src/sfizz/Debug.h +++ b/src/sfizz/Debug.h @@ -46,7 +46,7 @@ std::cerr << "Check failed at " << __FILE__ << ":" << __LINE__ << '\n'; \ } while (0) -#define CHECK(expression) \ +#define SFIZZ_CHECK(expression) \ do { \ if (!(expression)) { \ std::cerr << "Check failed: " << #expression << '\n'; \ @@ -59,7 +59,7 @@ #define ASSERTFALSE do {} while (0) #define ASSERT(expression) do {} while (0) #define CHECKFALSE do {} while (0) -#define CHECK(expression) do {} while (0) +#define SFIZZ_CHECK(expression) do {} while (0) #endif diff --git a/src/sfizz/Effects.cpp b/src/sfizz/Effects.cpp index 2787967b..26ee10ae 100644 --- a/src/sfizz/Effects.cpp +++ b/src/sfizz/Effects.cpp @@ -105,7 +105,7 @@ void EffectBus::addToInputs(const float* const addInput[], float addGain, unsign for (unsigned c = 0; c < EffectChannels; ++c) { absl::Span addIn { addInput[c], nframes }; - sfz::multiplyAdd(addGain, addIn, _inputs.getSpan(c).first(nframes)); + sfz::multiplyAdd1(addGain, addIn, _inputs.getSpan(c).first(nframes)); } } @@ -154,8 +154,8 @@ void EffectBus::mixOutputsTo(float* const mainOutput[], float* const mixOutput[] for (unsigned c = 0; c < EffectChannels; ++c) { auto fxOut = _outputs.getConstSpan(c).first(nframes); - sfz::multiplyAdd(gainToMain, fxOut, absl::Span(mainOutput[c], nframes)); - sfz::multiplyAdd(gainToMix, fxOut, absl::Span(mixOutput[c], nframes)); + sfz::multiplyAdd1(gainToMain, fxOut, absl::Span(mainOutput[c], nframes)); + sfz::multiplyAdd1(gainToMix, fxOut, absl::Span(mixOutput[c], nframes)); } } diff --git a/src/sfizz/MathHelpers.h b/src/sfizz/MathHelpers.h index 4a6aff49..b77ee5ee 100644 --- a/src/sfizz/MathHelpers.h +++ b/src/sfizz/MathHelpers.h @@ -491,7 +491,7 @@ constexpr bool checkSpanSizes(const absl::Span& span1, Others... others) return _checkSpanSizes(span1.size(), others...); } -#define CHECK_SPAN_SIZES(...) CHECK(checkSpanSizes(__VA_ARGS__)) +#define CHECK_SPAN_SIZES(...) SFIZZ_CHECK(checkSpanSizes(__VA_ARGS__)) class ScopedRoundingMode { diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index 8e02c6e9..7414ede7 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -18,326 +18,141 @@ namespace sfz { template struct SIMDDispatch { constexpr SIMDDispatch() = default; - void resetStatus(); bool getStatus(SIMDOps op) const; void setStatus(SIMDOps op, bool enable); - void (*writeInterleaved)(const T* inputLeft, const T* inputRight, T* output, unsigned outputSize) noexcept = &writeInterleavedScalar; - void (*readInterleaved)(const T* input, T* outputLeft, T* outputRight, unsigned inputSize) noexcept = &readInterleavedScalar; - void (*applyGain)(const T* gain, const T* input, T* output, unsigned size) noexcept = &applyGainScalar; - void (*applyGain1)(T gain, const T* input, T* output, unsigned size) noexcept = &applyGainScalar; - void (*divide)(const T* input, const T* divisor, T* output, unsigned size) noexcept = ÷Scalar; - void (*multiplyAdd)(const T* gain, const T* input, T* output, unsigned size) noexcept = &multiplyAddScalar; - void (*multiplyAdd1)(T gain, const T* input, T* output, unsigned size) noexcept = &multiplyAddScalar; - T (*linearRamp)(T* output, T start, T step, unsigned size) noexcept = &linearRampScalar; - T (*multiplicativeRamp)(T* output, T start, T step, unsigned size) noexcept = &multiplicativeRampScalar; - void (*add)(const T* input, T* output, unsigned size) noexcept = &addScalar; - void (*add1)(T value, T* output, unsigned size) noexcept = &addScalar; - void (*subtract)(const T* input, T* output, unsigned size) noexcept = &subtractScalar; - void (*subtract1)(T value, T* output, unsigned size) noexcept = &subtractScalar; - void (*copy)(const T* input, T* output, unsigned size) noexcept = ©Scalar; - void (*cumsum)(const T* input, T* output, unsigned size) noexcept = &cumsumScalar; - void (*diff)(const T* input, T* output, unsigned size) noexcept = &diffScalar; - T (*mean)(const T* vector, unsigned size) noexcept = &meanScalar; - T (*meanSquared)(const T* vector, unsigned size) noexcept = &meanSquaredScalar; + decltype(&writeInterleavedScalar) writeInterleaved = &writeInterleavedScalar; + decltype(&readInterleavedScalar) readInterleaved = &readInterleavedScalar; + decltype(&gainScalar) gain = &gainScalar; + decltype(&gain1Scalar) gain1 = &gain1Scalar; + decltype(÷Scalar) divide = ÷Scalar; + decltype(&multiplyAddScalar) multiplyAdd = &multiplyAddScalar; + decltype(&multiplyAdd1Scalar) multiplyAdd1 = &multiplyAdd1Scalar; + decltype(&linearRampScalar) linearRamp = &linearRampScalar; + decltype(&multiplicativeRampScalar) multiplicativeRamp = &multiplicativeRampScalar; + decltype(&addScalar) add = &addScalar; + decltype(&add1Scalar) add1 = &add1Scalar; + decltype(&subtractScalar) subtract = &subtractScalar; + decltype(&subtract1Scalar) subtract1 = &subtract1Scalar; + decltype(©Scalar) copy = ©Scalar; + decltype(&cumsumScalar) cumsum = &cumsumScalar; + decltype(&diffScalar) diff = &diffScalar; + decltype(&meanScalar) mean = &meanScalar; + decltype(&meanSquaredScalar) meanSquared = &meanSquaredScalar; private: std::array(SIMDOps::_sentinel)> simdStatus; + bool initialized { false }; + cpuid::cpuinfo info; }; -/// - -static SIMDDispatch simdDispatch; - -void resetSIMDOpStatus() -{ - simdDispatch.resetStatus(); -} - -void setSIMDOpStatus(SIMDOps op, bool status) -{ - simdDispatch.setStatus(op, status); -} - -bool getSIMDOpStatus(SIMDOps op) -{ - return simdDispatch.getStatus(op); -} - -/// - -void readInterleaved(const float* input, float* outputLeft, float* outputRight, unsigned inputSize) noexcept -{ - return simdDispatch.readInterleaved(input, outputLeft, outputRight, inputSize); -} - -void writeInterleaved(const float* inputLeft, const float* inputRight, float* output, unsigned outputSize) noexcept -{ - return simdDispatch.writeInterleaved(inputLeft, inputRight, output, outputSize); -} template <> -void applyGain(float gain, const float* input, float* output, unsigned size) noexcept -{ - return simdDispatch.applyGain1(gain, input, output, size); -} - -template <> -void applyGain(const float* gain, const float* input, float* output, unsigned size) noexcept -{ - return simdDispatch.applyGain(gain, input, output, size); -} - -template <> -void divide(const float* input, const float* divisor, float* output, unsigned size) noexcept -{ - return simdDispatch.divide(input, divisor, output, size); -} - -template <> -void multiplyAdd(const float* gain, const float* input, float* output, unsigned size) noexcept -{ - return simdDispatch.multiplyAdd(gain, input, output, size); -} - -template <> -void multiplyAdd(float gain, const float* input, float* output, unsigned size) noexcept -{ - return simdDispatch.multiplyAdd1(gain, input, output, size); -} - -template <> -float linearRamp(float* output, float start, float step, unsigned size) noexcept -{ - return simdDispatch.linearRamp(output, start, step, size); -} - -template <> -float multiplicativeRamp(float* output, float start, float step, unsigned size) noexcept -{ - return simdDispatch.multiplicativeRamp(output, start, step, size); -} - -template <> -void add(const float* input, float* output, unsigned size) noexcept -{ - return simdDispatch.add(input, output, size); -} - -template <> -void add(float value, float* output, unsigned size) noexcept -{ - return simdDispatch.add1(value, output, size); -} - -template <> -void subtract(const float* input, float* output, unsigned size) noexcept -{ - return simdDispatch.subtract(input, output, size); -} - -template <> -void subtract(float value, float* output, unsigned size) noexcept -{ - return simdDispatch.subtract1(value, output, size); -} - -template <> -void copy(const float* input, float* output, unsigned size) noexcept -{ - return simdDispatch.copy(input, output, size); -} - -template <> -float mean(const float* vector, unsigned size) noexcept -{ - return simdDispatch.mean(vector, size); -} - -template <> -float meanSquared(const float* vector, unsigned size) noexcept -{ - return simdDispatch.meanSquared(vector, size); -} - -template <> -void cumsum(const float* input, float* output, unsigned size) noexcept -{ - return simdDispatch.cumsum(input, output, size); -} - -template <> -void diff(const float* input, float* output, unsigned size) noexcept -{ - return simdDispatch.diff(input, output, size); -} - -/// - -static cpuid::cpuinfo& cpuInfo() -{ - static cpuid::cpuinfo info; - return info; -} - -template -bool SIMDDispatch::getStatus(SIMDOps op) const +bool SIMDDispatch::getStatus(SIMDOps op) const { const unsigned index = static_cast(op); ASSERT(index < simdStatus.size()); return simdStatus[index]; } -template -void SIMDDispatch::setStatus(SIMDOps op, bool enable) +template <> +void SIMDDispatch::setStatus(SIMDOps op, bool enable) { const unsigned index = static_cast(op); ASSERT(index < simdStatus.size()); - simdStatus[index] = enable; - const cpuid::cpuinfo& info = cpuInfo(); - bool useSSE = enable && info.has_sse(); - bool useAVX = enable && info.has_avx(); - - switch (op) { - default: - break; - - case SIMDOps::writeInterleaved: - if (useSSE) - writeInterleaved = &writeInterleavedSSE; - else - writeInterleaved = &writeInterleavedScalar; - break; - - case SIMDOps::readInterleaved: - if (useSSE) - readInterleaved = &readInterleavedSSE; - else - readInterleaved = &readInterleavedScalar; - break; - - case SIMDOps::gain: - if (useAVX) { - applyGain = &applyGainAVX; - applyGain1 = &applyGainAVX; - } - else if (useSSE) { - applyGain = &applyGainSSE; - applyGain1 = &applyGainSSE; - } - else { - applyGain = &applyGainScalar; - applyGain1 = &applyGainScalar; - } - break; - - case SIMDOps::divide: - if (useSSE) - divide = ÷SSE; - else - divide = ÷Scalar; - break; - - case SIMDOps::multiplyAdd: - if (useSSE) { - multiplyAdd = &multiplyAddSSE; - multiplyAdd1 = &multiplyAddSSE; - } - else { - multiplyAdd = &multiplyAddScalar; - multiplyAdd1 = &multiplyAddScalar; - } - break; - - case SIMDOps::linearRamp: - if (useSSE) - linearRamp = &linearRampSSE; - else - linearRamp = &linearRampScalar; - break; - - case SIMDOps::multiplicativeRamp: - if (useSSE) - multiplicativeRamp = &multiplicativeRampSSE; - else - multiplicativeRamp = &multiplicativeRampScalar; - break; - - case SIMDOps::add: - if (useSSE) { - add = &addSSE; - add1 = &addSSE; - } - else { - add = &addScalar; - add1 = &addScalar; - } - break; - - case SIMDOps::subtract: - if (useSSE) { - subtract = &subtractSSE; - subtract1 = &subtractSSE; - } - else { - subtract = &subtractScalar; - subtract1 = &subtractScalar; - } - break; - - case SIMDOps::copy: - if (useSSE) - copy = ©SSE; - else - copy = ©Scalar; - break; - - case SIMDOps::cumsum: - if (useSSE) - cumsum = &cumsumSSE; - else - cumsum = &cumsumScalar; - break; - - case SIMDOps::diff: - if (useSSE) - diff = &diffSSE; - else - diff = &diffScalar; - break; - - case SIMDOps::mean: - if (useSSE) - mean = &meanSSE; - else - mean = &meanScalar; - break; - - case SIMDOps::meanSquared: - if (useSSE) - meanSquared = &meanSquaredSSE; - else - meanSquared = &meanSquaredScalar; - break; + if (!enable) { +#define SIMD_OP(opname) case SIMDOps::opname : (opname) = opname ## Scalar; return; + switch (op) { + default: break; + SIMD_OP(writeInterleaved) + SIMD_OP(readInterleaved) + SIMD_OP(gain) + SIMD_OP(gain1) + SIMD_OP(divide) + SIMD_OP(linearRamp) + SIMD_OP(multiplicativeRamp) + SIMD_OP(add) + SIMD_OP(add1) + SIMD_OP(subtract) + SIMD_OP(subtract1) + SIMD_OP(multiplyAdd) + SIMD_OP(multiplyAdd1) + SIMD_OP(copy) + SIMD_OP(cumsum) + SIMD_OP(diff) + SIMD_OP(mean) + SIMD_OP(meanSquared) + } +#undef SIMD_OP } + +#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 +#define SIMD_OP(opname) case SIMDOps::opname : (opname) = opname ## AVX; return; + if (info.has_avx()) { + switch (op) { + default: break; + } + } +#undef SIMD_OP + +#define SIMD_OP(opname) case SIMDOps::opname : (opname) = opname ## SSE; return; + if (info.has_sse()) { + switch (op) { + default: break; + SIMD_OP(writeInterleaved) + SIMD_OP(readInterleaved) + SIMD_OP(gain) + SIMD_OP(gain1) + SIMD_OP(divide) + SIMD_OP(linearRamp) + SIMD_OP(multiplicativeRamp) + SIMD_OP(add) + SIMD_OP(add1) + SIMD_OP(subtract) + SIMD_OP(subtract1) + SIMD_OP(multiplyAdd) + SIMD_OP(multiplyAdd1) + SIMD_OP(copy) + SIMD_OP(cumsum) + SIMD_OP(diff) + SIMD_OP(mean) + SIMD_OP(meanSquared) + } + } +#undef SIMD_OP +#endif // SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386 + +#if SFIZZ_CPU_FAMILY_AARCH64 || SFIZZ_CPU_FAMILY_ARM +#define SIMD_OP(opname) case SIMDOps::opname : (opname) = opname ## NEON; return; + if (info.has_neon()) { + switch (op) { + default: break; + } + } +#undef SIMD_OP +#endif // SFIZZ_CPU_FAMILY_AARCH64 || SFIZZ_CPU_FAMILY_ARM } -template -void SIMDDispatch::resetStatus() +template <> +void SIMDDispatch::resetStatus() { setStatus(SIMDOps::writeInterleaved, false); setStatus(SIMDOps::readInterleaved, false); setStatus(SIMDOps::fill, true); setStatus(SIMDOps::gain, true); + setStatus(SIMDOps::gain1, true); setStatus(SIMDOps::divide, false); setStatus(SIMDOps::linearRamp, false); setStatus(SIMDOps::multiplicativeRamp, true); setStatus(SIMDOps::add, false); + setStatus(SIMDOps::add1, false); setStatus(SIMDOps::subtract, false); + setStatus(SIMDOps::subtract1, false); setStatus(SIMDOps::multiplyAdd, false); + setStatus(SIMDOps::multiplyAdd1, false); setStatus(SIMDOps::copy, false); setStatus(SIMDOps::cumsum, true); setStatus(SIMDOps::diff, false); @@ -349,17 +164,142 @@ void SIMDDispatch::resetStatus() /// -static volatile bool simdInitialized = false; -static std::mutex simdMutex; - -SIMDInitializer::SIMDInitializer() +template +static SIMDDispatch& simdDispatch() { - std::lock_guard lock { simdMutex }; + static SIMDDispatch dispatch; + return dispatch; +} - if (!simdInitialized) { - simdDispatch.resetStatus(); - simdInitialized = true; - } +template<> +void resetSIMDOpStatus() +{ + simdDispatch().resetStatus(); +} + +template<> +void setSIMDOpStatus(SIMDOps op, bool status) +{ + simdDispatch().setStatus(op, status); +} + +template<> +bool getSIMDOpStatus(SIMDOps op) +{ + return simdDispatch().getStatus(op); +} + +void initializeSIMDDispatchers() +{ + simdDispatch().resetStatus(); +} + +/// + +void readInterleaved(const float* input, float* outputLeft, float* outputRight, unsigned inputSize) noexcept +{ + return simdDispatch().readInterleaved(input, outputLeft, outputRight, inputSize); +} + +void writeInterleaved(const float* inputLeft, const float* inputRight, float* output, unsigned outputSize) noexcept +{ + return simdDispatch().writeInterleaved(inputLeft, inputRight, output, outputSize); +} + +template <> +void applyGain1(float gain, const float* input, float* output, unsigned size) noexcept +{ + return simdDispatch().gain1(gain, input, output, size); +} + +template <> +void applyGain(const float* gain, const float* input, float* output, unsigned size) noexcept +{ + return simdDispatch().gain(gain, input, output, size); +} + +template <> +void divide(const float* input, const float* divisor, float* output, unsigned size) noexcept +{ + return simdDispatch().divide(input, divisor, output, size); +} + +template <> +void multiplyAdd(const float* gain, const float* input, float* output, unsigned size) noexcept +{ + return simdDispatch().multiplyAdd(gain, input, output, size); +} + +template <> +void multiplyAdd1(float gain, const float* input, float* output, unsigned size) noexcept +{ + return simdDispatch().multiplyAdd1(gain, input, output, size); +} + +template <> +float linearRamp(float* output, float start, float step, unsigned size) noexcept +{ + return simdDispatch().linearRamp(output, start, step, size); +} + +template <> +float multiplicativeRamp(float* output, float start, float step, unsigned size) noexcept +{ + return simdDispatch().multiplicativeRamp(output, start, step, size); +} + +template <> +void add(const float* input, float* output, unsigned size) noexcept +{ + return simdDispatch().add(input, output, size); +} + +template <> +void add1(float value, float* output, unsigned size) noexcept +{ + return simdDispatch().add1(value, output, size); +} + +template <> +void subtract(const float* input, float* output, unsigned size) noexcept +{ + return simdDispatch().subtract(input, output, size); +} + +template <> +void subtract1(float value, float* output, unsigned size) noexcept +{ + return simdDispatch().subtract1(value, output, size); +} + +template <> +void copy(const float* input, float* output, unsigned size) noexcept +{ + return simdDispatch().copy(input, output, size); +} + +template <> +float mean(const float* vector, unsigned size) noexcept +{ + return simdDispatch().mean(vector, size); +} + +template <> +float meanSquared(const float* vector, unsigned size) noexcept +{ + return simdDispatch().meanSquared(vector, size); +} + +template <> +void cumsum(const float* input, float* output, unsigned size) noexcept +{ + return simdDispatch().cumsum(input, output, size); +} + +template <> +void diff(const float* input, float* output, unsigned size) noexcept +{ + return simdDispatch().diff(input, output, size); } } diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index 7379875d..ec27824a 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -42,12 +42,16 @@ enum class SIMDOps { readInterleaved, fill, gain, + gain1, divide, linearRamp, multiplicativeRamp, add, + add1, subtract, + subtract1, multiplyAdd, + multiplyAdd1, copy, cumsum, diff, @@ -58,15 +62,28 @@ enum class SIMDOps { _sentinel // }; +// Call this at least once before using SIMD operations +void initializeSIMDDispatchers(); + // Enable or disable SIMD accelerators at runtime +template void resetSIMDOpStatus(); + +template void setSIMDOpStatus(SIMDOps op, bool status); + +template bool getSIMDOpStatus(SIMDOps op); -// Initializer object which ensures to prepare SIMD dispatch -struct SIMDInitializer { - SIMDInitializer(); -}; +// Float specializations +template<> +void resetSIMDOpStatus(); + +template<> +void setSIMDOpStatus(SIMDOps op, bool status); + +template<> +bool getSIMDOpStatus(SIMDOps op); /** * @brief Read interleaved stereo data from a buffer and separate it in a left/right pair of buffers. @@ -81,8 +98,8 @@ void readInterleaved(const float* input, float* outputLeft, float* outputRight, inline void readInterleaved(absl::Span input, absl::Span outputLeft, absl::Span outputRight) noexcept { // Something is fishy with the sizes - CHECK(outputLeft.size() == input.size() / 2); - CHECK(outputRight.size() == input.size() / 2); + SFIZZ_CHECK(outputLeft.size() == input.size() / 2); + SFIZZ_CHECK(outputRight.size() == input.size() / 2); const auto size = min(input.size(), 2 * outputLeft.size(), 2 * outputRight.size()); readInterleaved(input.data(), outputLeft.data(), outputRight.data(), size); } @@ -100,8 +117,8 @@ void writeInterleaved(const float* inputLeft, const float* inputRight, float* ou inline void writeInterleaved(absl::Span inputLeft, absl::Span inputRight, absl::Span output) noexcept { // Something is fishy with the sizes - CHECK(inputLeft.size() == output.size() / 2); - CHECK(inputRight.size() == output.size() / 2); + SFIZZ_CHECK(inputLeft.size() == output.size() / 2); + SFIZZ_CHECK(inputRight.size() == output.size() / 2); const auto size = min(output.size(), 2 * inputLeft.size(), 2 * inputRight.size()); writeInterleaved(inputLeft.data(), inputRight.data(), output.data(), size); } @@ -134,19 +151,19 @@ void fill(absl::Span output, T value) noexcept * @param size */ template -void applyGain(T gain, const T* input, T* output, unsigned size) noexcept +void applyGain1(T gain, const T* input, T* output, unsigned size) noexcept { - applyGainScalar(gain, input, output, size); + gain1Scalar(gain, input, output, size); } template<> -void applyGain(float gain, const float* input, float* output, unsigned size) noexcept; +void applyGain1(float gain, const float* input, float* output, unsigned size) noexcept; template -inline void applyGain(T gain, absl::Span input, absl::Span output) noexcept +inline void applyGain1(T gain, absl::Span input, absl::Span output) noexcept { CHECK_SPAN_SIZES(input, output); - applyGain(gain, input.data(), output.data(), minSpanSize(input, output)); + applyGain1(gain, input.data(), output.data(), minSpanSize(input, output)); } /** @@ -157,15 +174,15 @@ inline void applyGain(T gain, absl::Span input, absl::Span output) n * @param size */ template -inline void applyGain(float gain, float* array, unsigned size) noexcept +inline void applyGain1(float gain, float* array, unsigned size) noexcept { - applyGain(gain, array, array, size); + applyGain1(gain, array, array, size); } template -inline void applyGain(float gain, absl::Span array) noexcept +inline void applyGain1(float gain, absl::Span array) noexcept { - applyGain(gain, array.data(), array.data(), array.size()); + applyGain1(gain, array.data(), array.data(), array.size()); } /** @@ -179,7 +196,7 @@ inline void applyGain(float gain, absl::Span array) noexcept template void applyGain(const T* gain, const T* input, T* output, unsigned size) noexcept { - applyGainScalar(gain, input, output, size); + gainScalar(gain, input, output, size); } template<> @@ -288,19 +305,19 @@ void multiplyAdd(absl::Span gain, absl::Span input, absl::Span * @param size */ template -void multiplyAdd(T gain, const T* input, T* output, unsigned size) noexcept +void multiplyAdd1(T gain, const T* input, T* output, unsigned size) noexcept { - multiplyAddScalar(gain, input, output, size); + multiplyAdd1Scalar(gain, input, output, size); } template <> -void multiplyAdd(float gain, const float* input, float* output, unsigned size) noexcept; +void multiplyAdd1(float gain, const float* input, float* output, unsigned size) noexcept; template -void multiplyAdd(T gain, absl::Span input, absl::Span output) noexcept +void multiplyAdd1(T gain, absl::Span input, absl::Span output) noexcept { CHECK_SPAN_SIZES(input, output); - multiplyAdd(gain, input.data(), output.data(), minSpanSize(input, output)); + multiplyAdd1(gain, input.data(), output.data(), minSpanSize(input, output)); } /** @@ -386,18 +403,18 @@ void add(absl::Span input, absl::Span output) noexcept * @param size */ template -void add(T value, T* output, unsigned size) noexcept +void add1(T value, T* output, unsigned size) noexcept { - addScalar(value, output, size); + add1Scalar(value, output, size); } template <> -void add(float value, float* output, unsigned size) noexcept; +void add1(float value, float* output, unsigned size) noexcept; template -void add(T value, absl::Span output) noexcept +void add1(T value, absl::Span output) noexcept { - add(value, output.data(), output.size()); + add1(value, output.data(), output.size()); } /** @@ -433,18 +450,18 @@ void subtract(absl::Span input, absl::Span output) noexcept * @param size */ template -void subtract(T value, T* output, unsigned size) noexcept +void subtract1(T value, T* output, unsigned size) noexcept { - subtractScalar(value, output, size); + subtract1Scalar(value, output, size); } template <> -void subtract(float value, float* output, unsigned size) noexcept; +void subtract1(float value, float* output, unsigned size) noexcept; template -void subtract(T value, absl::Span output) noexcept +void subtract1(T value, absl::Span output) noexcept { - subtract(value, output.data(), output.size()); + subtract1(value, output.data(), output.size()); } /** @@ -568,8 +585,8 @@ namespace _internals { template void sfzInterpolationCast(absl::Span floatJumps, absl::Span jumps, absl::Span coeffs) noexcept { - CHECK(jumps.size() >= floatJumps.size()); - CHECK(jumps.size() == coeffs.size()); + SFIZZ_CHECK(jumps.size() >= floatJumps.size()); + SFIZZ_CHECK(jumps.size() == coeffs.size()); auto floatJump = floatJumps.data(); auto jump = jumps.data(); diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 5fa4827b..422e922b 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -24,6 +24,7 @@ sfz::Synth::Synth() : Synth(config::numVoices) { + initializeSIMDDispatchers(); } sfz::Synth::Synth(int numVoices) @@ -524,7 +525,7 @@ float sfz::Synth::getTuningFrequency() const void sfz::Synth::loadStretchTuningByRatio(float ratio) { - CHECK(ratio >= 0.0f && ratio <= 1.0f); + SFIZZ_CHECK(ratio >= 0.0f && ratio <= 1.0f); ratio = clamp(ratio, 0.0f, 1.0f); if (ratio > 0.0f) @@ -747,8 +748,8 @@ void sfz::Synth::renderBlock(AudioSpan buffer) noexcept ASSERT(!hasNanInf(buffer.getConstSpan(0))); ASSERT(!hasNanInf(buffer.getConstSpan(1))); - CHECK(isReasonableAudio(buffer.getConstSpan(0))); - CHECK(isReasonableAudio(buffer.getConstSpan(1))); + SFIZZ_CHECK(isReasonableAudio(buffer.getConstSpan(0))); + SFIZZ_CHECK(isReasonableAudio(buffer.getConstSpan(1))); } void sfz::Synth::noteOn(int delay, int noteNumber, uint8_t velocity) noexcept @@ -1129,14 +1130,14 @@ int sfz::Synth::getSampleQuality(ProcessMode mode) case ProcessFreewheeling: return resources.synthConfig.freeWheelingSampleQuality; default: - CHECK(false); + SFIZZ_CHECK(false); return 0; } } void sfz::Synth::setSampleQuality(ProcessMode mode, int quality) { - CHECK(quality >= 1 && quality <= 10); + SFIZZ_CHECK(quality >= 1 && quality <= 10); quality = clamp(quality, 1, 10); switch (mode) { @@ -1147,7 +1148,7 @@ void sfz::Synth::setSampleQuality(ProcessMode mode, int quality) resources.synthConfig.freeWheelingSampleQuality = quality; break; default: - CHECK(false); + SFIZZ_CHECK(false); break; } } diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 597b986b..63a723de 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -264,8 +264,8 @@ void sfz::Voice::renderBlock(AudioSpan buffer) noexcept #if 0 ASSERT(!hasNanInf(buffer.getConstSpan(0))); ASSERT(!hasNanInf(buffer.getConstSpan(1))); - CHECK(isReasonableAudio(buffer.getConstSpan(0))); - CHECK(isReasonableAudio(buffer.getConstSpan(1))); + SFIZZ_CHECK(isReasonableAudio(buffer.getConstSpan(0))); + SFIZZ_CHECK(isReasonableAudio(buffer.getConstSpan(1))); #endif } @@ -282,7 +282,7 @@ void sfz::Voice::amplitudeEnvelope(absl::Span modulationSpan) noexcept egEnvelope.getBlock(modulationSpan); // Amplitude envelope - applyGain(baseGain, modulationSpan); + applyGain1(baseGain, modulationSpan); for (const auto& mod : region->amplitudeCC) { linearModifier(resources, *tempSpan, mod, normalizePercents); applyGain(*tempSpan, modulationSpan); @@ -305,7 +305,7 @@ void sfz::Voice::amplitudeEnvelope(absl::Span modulationSpan) noexcept } // Volume envelope - applyGain(db2mag(baseVolumedB), modulationSpan); + applyGain1(db2mag(baseVolumedB), modulationSpan); for (const auto& mod : region->volumeCC) { multiplicativeModifier(resources, *tempSpan, mod, [](float x) { return db2mag(x); @@ -480,7 +480,7 @@ void sfz::Voice::fillWithData(AudioSpan buffer) noexcept jumps->front() += floatPositionOffset; cumsum(*jumps, *jumps); sfzInterpolationCast(*jumps, *indices, *coeffs); - add(sourcePosition, *indices); + add1(sourcePosition, *indices); if (region->shouldLoop() && region->loopEnd(currentPromise->oversamplingFactor) <= source.getNumFrames()) { const auto loopEnd = static_cast(region->loopEnd(currentPromise->oversamplingFactor)); @@ -488,7 +488,7 @@ void sfz::Voice::fillWithData(AudioSpan buffer) noexcept for (auto* index = indices->begin(); index < indices->end(); ++index) { if (*index > loopEnd) { const auto remainingElements = static_cast(std::distance(index, indices->end())); - subtract(offset, { index, remainingElements }); + subtract1(offset, { index, remainingElements }); } } } else { @@ -542,8 +542,8 @@ void sfz::Voice::fillWithData(AudioSpan buffer) noexcept #if 0 ASSERT(!hasNanInf(buffer.getConstSpan(0))); ASSERT(!hasNanInf(buffer.getConstSpan(1))); - CHECK(isReasonableAudio(buffer.getConstSpan(0))); - CHECK(isReasonableAudio(buffer.getConstSpan(1))); + SFIZZ_CHECK(isReasonableAudio(buffer.getConstSpan(0))); + SFIZZ_CHECK(isReasonableAudio(buffer.getConstSpan(1))); #endif } @@ -624,8 +624,8 @@ void sfz::Voice::fillWithGenerator(AudioSpan buffer) noexcept for (unsigned i = 0, n = waveUnisonSize; i < n; ++i) { WavetableOscillator& osc = waveOscillators[i]; osc.processModulated(frequencies->data(), waveDetuneRatio[i], tempSpan->data(), numFrames); - sfz::multiplyAdd(waveLeftGain[i], *tempSpan, leftSpan); - sfz::multiplyAdd(waveRightGain[i], *tempSpan, rightSpan); + multiplyAdd1(waveLeftGain[i], *tempSpan, leftSpan); + multiplyAdd1(waveRightGain[i], *tempSpan, rightSpan); } } } @@ -633,8 +633,8 @@ void sfz::Voice::fillWithGenerator(AudioSpan buffer) noexcept #if 0 ASSERT(!hasNanInf(buffer.getConstSpan(0))); ASSERT(!hasNanInf(buffer.getConstSpan(1))); - CHECK(isReasonableAudio(buffer.getConstSpan(0))); - CHECK(isReasonableAudio(buffer.getConstSpan(1))); + SFIZZ_CHECK(isReasonableAudio(buffer.getConstSpan(0))); + SFIZZ_CHECK(isReasonableAudio(buffer.getConstSpan(1))); #endif } diff --git a/src/sfizz/effects/Strings.cpp b/src/sfizz/effects/Strings.cpp index db48ca77..dfaa0656 100644 --- a/src/sfizz/effects/Strings.cpp +++ b/src/sfizz/effects/Strings.cpp @@ -103,8 +103,8 @@ namespace fx { // mix down the stereo signal to create the resonator excitation source absl::Span resInput = _tempBuffer.getSpan(0).first(nframes); - sfz::applyGain(M_SQRT1_2, inputL, resInput); - sfz::multiplyAdd(M_SQRT1_2, inputR, resInput); + sfz::applyGain1(M_SQRT1_2, inputL, resInput); + sfz::multiplyAdd1(M_SQRT1_2, inputR, resInput); // generate the strings summed into a common buffer absl::Span resOutput = _tempBuffer.getSpan(1).first(nframes); diff --git a/src/sfizz/simd/HelpersAVX.cpp b/src/sfizz/simd/HelpersAVX.cpp index d9bcd1d7..8fff4dc8 100644 --- a/src/sfizz/simd/HelpersAVX.cpp +++ b/src/sfizz/simd/HelpersAVX.cpp @@ -16,7 +16,7 @@ constexpr unsigned TypeAlignment = 8; constexpr unsigned ByteAlignment = TypeAlignment * sizeof(Type); #endif -void applyGainAVX(float gain, const float* input, float* output, unsigned size) noexcept +void gain1AVX(float gain, const float* input, float* output, unsigned size) noexcept { const auto sentinel = output + size; @@ -36,7 +36,7 @@ void applyGainAVX(float gain, const float* input, float* output, unsigned size) *output++ = gain * (*input++); } -void applyGainAVX(const float* gain, const float* input, float* output, unsigned size) noexcept +void gainAVX(const float* gain, const float* input, float* output, unsigned size) noexcept { const auto sentinel = output + size; diff --git a/src/sfizz/simd/HelpersAVX.h b/src/sfizz/simd/HelpersAVX.h index 7eb8c2bf..e3c7b90a 100644 --- a/src/sfizz/simd/HelpersAVX.h +++ b/src/sfizz/simd/HelpersAVX.h @@ -6,5 +6,5 @@ #pragma once -void applyGainAVX(float gain, const float* input, float* output, unsigned size) noexcept; -void applyGainAVX(const float* gain, const float* input, float* output, unsigned size) noexcept; +void gain1AVX(float gain, const float* input, float* output, unsigned size) noexcept; +void gainAVX(const float* gain, const float* input, float* output, unsigned size) noexcept; diff --git a/src/sfizz/simd/HelpersSSE.cpp b/src/sfizz/simd/HelpersSSE.cpp index 12fc77a4..079d6a75 100644 --- a/src/sfizz/simd/HelpersSSE.cpp +++ b/src/sfizz/simd/HelpersSSE.cpp @@ -82,7 +82,7 @@ void writeInterleavedSSE(const float* inputLeft, const float* inputRight, float* } } -void applyGainSSE(float gain, const float* input, float* output, unsigned size) noexcept +void gain1SSE(float gain, const float* input, float* output, unsigned size) noexcept { const auto sentinel = output + size; @@ -102,7 +102,7 @@ void applyGainSSE(float gain, const float* input, float* output, unsigned size) *output++ = gain * (*input++); } -void applyGainSSE(const float* gain, const float* input, float* output, unsigned size) noexcept +void gainSSE(const float* gain, const float* input, float* output, unsigned size) noexcept { const auto sentinel = output + size; @@ -161,7 +161,7 @@ void multiplyAddSSE(const float* gain, const float* input, float* output, unsign *output++ += (*gain++) * (*input++); } -void multiplyAddSSE(float gain, const float* input, float* output, unsigned size) noexcept +void multiplyAdd1SSE(float gain, const float* input, float* output, unsigned size) noexcept { const auto sentinel = output + size; @@ -260,7 +260,7 @@ void addSSE(const float* input, float* output, unsigned size) noexcept *output++ += *input++; } -void addSSE(float value, float* output, unsigned size) noexcept +void add1SSE(float value, float* output, unsigned size) noexcept { const auto sentinel = output + size; @@ -299,7 +299,7 @@ void subtractSSE(const float* input, float* output, unsigned size) noexcept *output++ -= *input++; } -void subtractSSE(float value, float* output, unsigned size) noexcept +void subtract1SSE(float value, float* output, unsigned size) noexcept { const auto sentinel = output + size; diff --git a/src/sfizz/simd/HelpersSSE.h b/src/sfizz/simd/HelpersSSE.h index 9c43e342..a6d5e0a5 100644 --- a/src/sfizz/simd/HelpersSSE.h +++ b/src/sfizz/simd/HelpersSSE.h @@ -9,17 +9,17 @@ /* These are the SSE versions of the SIMDHelpers */ void readInterleavedSSE(const float* input, float* outputLeft, float* outputRight, unsigned inputSize) noexcept; void writeInterleavedSSE(const float* inputLeft, const float* inputRight, float* output, unsigned outputSize) noexcept; -void applyGainSSE(float gain, const float* input, float* output, unsigned size) noexcept; -void applyGainSSE(const float* gain, const float* input, float* output, unsigned size) noexcept; +void gainSSE(const float* gain, const float* input, float* output, unsigned size) noexcept; +void gain1SSE(float gain, const float* input, float* output, unsigned size) noexcept; void divideSSE(const float* input, const float* divisor, float* output, unsigned size) noexcept; void multiplyAddSSE(const float* gain, const float* input, float* output, unsigned size) noexcept; -void multiplyAddSSE(float gain, const float* input, float* output, unsigned size) noexcept; +void multiplyAdd1SSE(float gain, const float* input, float* output, unsigned size) noexcept; float linearRampSSE(float* output, float start, float step, unsigned size) noexcept; float multiplicativeRampSSE(float* output, float start, float step, unsigned size) noexcept; void addSSE(const float* input, float* output, unsigned size) noexcept; -void addSSE(float value, float* output, unsigned size) noexcept; +void add1SSE(float value, float* output, unsigned size) noexcept; void subtractSSE(const float* input, float* output, unsigned size) noexcept; -void subtractSSE(float value, float* output, unsigned size) noexcept; +void subtract1SSE(float value, float* output, unsigned size) noexcept; void copySSE(const float* input, float* output, unsigned size) noexcept; float meanSSE(const float* vector, unsigned size) noexcept; float meanSquaredSSE(const float* vector, unsigned size) noexcept; diff --git a/src/sfizz/simd/HelpersScalar.h b/src/sfizz/simd/HelpersScalar.h index d24b75ea..ab1415a7 100644 --- a/src/sfizz/simd/HelpersScalar.h +++ b/src/sfizz/simd/HelpersScalar.h @@ -28,7 +28,7 @@ inline void writeInterleavedScalar(const T* inputLeft, const T* inputRight, T* o } template -inline void applyGainScalar(T gain, const T* input, T* output, unsigned size) noexcept +inline void gain1Scalar(T gain, const T* input, T* output, unsigned size) noexcept { const auto sentinel = output + size; while (output < sentinel) @@ -36,7 +36,7 @@ inline void applyGainScalar(T gain, const T* input, T* output, unsigned size) no } template -inline void applyGainScalar(const T* gain, const T* input, T* output, unsigned size) noexcept +inline void gainScalar(const T* gain, const T* input, T* output, unsigned size) noexcept { const auto sentinel = output + size; while (output < sentinel) @@ -60,7 +60,7 @@ inline void multiplyAddScalar(const T* gain, const T* input, T* output, unsigned } template -inline void multiplyAddScalar(T gain, const T* input, T* output, unsigned size) noexcept +inline void multiplyAdd1Scalar(T gain, const T* input, T* output, unsigned size) noexcept { const auto sentinel = output + size; while (output < sentinel) @@ -98,7 +98,7 @@ inline void addScalar(const T* input, T* output, unsigned size) noexcept } template -inline void addScalar(T value, T* output, unsigned size) noexcept +inline void add1Scalar(T value, T* output, unsigned size) noexcept { const auto sentinel = output + size; while (output < sentinel) @@ -114,7 +114,7 @@ inline void subtractScalar(const T* input, T* output, unsigned size) noexcept } template -inline void subtractScalar(T value, T* output, unsigned size) noexcept +inline void subtract1Scalar(T value, T* output, unsigned size) noexcept { const auto sentinel = output + size; while (output < sentinel) diff --git a/tests/MainT.cpp b/tests/MainT.cpp index 40865cab..a72f67db 100644 --- a/tests/MainT.cpp +++ b/tests/MainT.cpp @@ -5,8 +5,6 @@ int main(int argc, char* argv[]) { - sfz::SIMDInitializer simdInit; - int result = Catch::Session().run(argc, argv); return result; } diff --git a/tests/SIMDHelpersT.cpp b/tests/SIMDHelpersT.cpp index 415406fd..9a7c9175 100644 --- a/tests/SIMDHelpersT.cpp +++ b/tests/SIMDHelpersT.cpp @@ -55,7 +55,7 @@ TEST_CASE("[Helpers] Interleaved read") std::array expected { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f }; std::array leftOutput; std::array rightOutput; - sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; @@ -73,7 +73,7 @@ TEST_CASE("[Helpers] Interleaved read unaligned end") std::array expected { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f }; std::array leftOutput; std::array rightOutput; - sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; @@ -91,7 +91,7 @@ TEST_CASE("[Helpers] Small interleaved read unaligned end") std::array expected { 0.0f, 1.0f, 2.0f, 10.0f, 11.0f, 12.0f }; std::array leftOutput; std::array rightOutput; - sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; @@ -109,7 +109,7 @@ TEST_CASE("[Helpers] Interleaved read -- SIMD") std::array expected = { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f }; std::array leftOutput; std::array rightOutput; - sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; @@ -127,7 +127,7 @@ TEST_CASE("[Helpers] Interleaved read unaligned end -- SIMD") std::array expected = { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f }; std::array leftOutput; std::array rightOutput; - sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; @@ -145,7 +145,7 @@ TEST_CASE("[Helpers] Small interleaved read unaligned end -- SIMD") std::array expected { 0.0f, 1.0f, 2.0f, 10.0f, 11.0f, 12.0f }; std::array leftOutput; std::array rightOutput; - sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; @@ -165,9 +165,9 @@ TEST_CASE("[Helpers] Interleaved read SIMD vs Scalar") std::array leftOutputSIMD; std::array rightOutputSIMD; std::iota(input.begin(), input.end(), 0.0f); - sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); sfz::readInterleaved(input, absl::MakeSpan(leftOutputScalar), absl::MakeSpan(rightOutputScalar)); - sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); sfz::readInterleaved(input, absl::MakeSpan(leftOutputSIMD), absl::MakeSpan(rightOutputSIMD)); REQUIRE(leftOutputScalar == leftOutputSIMD); REQUIRE(rightOutputScalar == rightOutputSIMD); @@ -188,7 +188,7 @@ TEST_CASE("[Helpers] Interleaved write") std::array rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f }; std::array output; std::array expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f }; - sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -199,7 +199,7 @@ TEST_CASE("[Helpers] Interleaved write unaligned end") std::array rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f }; std::array output; std::array expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f, 8.0f, 18.0f, 9.0f, 19.0f }; - sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -210,7 +210,7 @@ TEST_CASE("[Helpers] Small interleaved write unaligned end") std::array rightInput { 10.0f, 11.0f, 12.0f }; std::array output; std::array expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f }; - sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -230,7 +230,7 @@ TEST_CASE("[Helpers] Interleaved write -- SIMD") std::array rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f }; std::array output; std::array expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f }; - sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true); sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -251,7 +251,7 @@ TEST_CASE("[Helpers] Small interleaved write unaligned end -- SIMD") std::array rightInput { 10.0f, 11.0f, 12.0f }; std::array output; std::array expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f }; - sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true); sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -264,9 +264,9 @@ TEST_CASE("[Helpers] Interleaved write SIMD vs Scalar") std::array outputSIMD; std::iota(leftInput.begin(), leftInput.end(), 0.0f); std::iota(rightInput.begin(), rightInput.end(), static_cast(medBufferSize)); - sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(outputScalar)); - sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true); sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(outputSIMD)); REQUIRE(outputScalar == outputSIMD); } @@ -281,16 +281,16 @@ TEST_CASE("[Helpers] Gain, single") SECTION("Scalar") { std::array output; - sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); - sfz::applyGain(fillValue, input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain1, false); + sfz::applyGain1(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)); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain1, true); + sfz::applyGain1(fillValue, input, absl::MakeSpan(output)); REQUIRE(output == expected); } } @@ -303,15 +303,15 @@ TEST_CASE("[Helpers] Gain, single and inplace") SECTION("Scalar") { absl::c_fill(buffer, 1.0f); - sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); - sfz::applyGain(fillValue, buffer, absl::MakeSpan(buffer)); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain1, false); + sfz::applyGain1(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)); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain1, false); + sfz::applyGain1(fillValue, buffer, absl::MakeSpan(buffer)); REQUIRE(buffer == expected); } } @@ -328,7 +328,7 @@ TEST_CASE("[Helpers] Gain, spans") SECTION("Scalar") { std::array output; - sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); sfz::applyGain(gain, input, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -336,7 +336,7 @@ TEST_CASE("[Helpers] Gain, spans") SECTION("SIMD") { std::array output; - sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); sfz::applyGain(gain, input, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -353,7 +353,7 @@ TEST_CASE("[Helpers] Gain, spans and inplace") SECTION("Scalar") { absl::c_fill(buffer, 1.0f); - sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); sfz::applyGain(gain, buffer, absl::MakeSpan(buffer)); REQUIRE(buffer == expected); } @@ -361,7 +361,7 @@ TEST_CASE("[Helpers] Gain, spans and inplace") SECTION("SIMD") { absl::c_fill(buffer, 1.0f); - sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); sfz::applyGain(gain, buffer, absl::MakeSpan(buffer)); REQUIRE(buffer == expected); } @@ -373,7 +373,7 @@ TEST_CASE("[Helpers] Linear Ramp") const float v { fillValue }; std::array output; std::array expected { start, start + v, start + v + v, start + v + v + v, start + v + v + v + v, start + v + v + v + v + v }; - sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, false); sfz::linearRamp(absl::MakeSpan(output), start, v); REQUIRE(output == expected); } @@ -384,7 +384,7 @@ TEST_CASE("[Helpers] Linear Ramp (SIMD)") const float v { fillValue }; std::array output; std::array expected { start, start + v, start + v + v, start + v + v + v, start + v + v + v + v, start + v + v + v + v + v }; - sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); sfz::linearRamp(absl::MakeSpan(output), start, v); REQUIRE(approxEqual(output, expected)); } @@ -394,9 +394,9 @@ TEST_CASE("[Helpers] Linear Ramp (SIMD vs scalar)") const float start { 0.0f }; std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); - sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, false); sfz::linearRamp(absl::MakeSpan(outputScalar), start, fillValue); - sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); sfz::linearRamp(absl::MakeSpan(outputSIMD), start, fillValue); REQUIRE(approxEqual(outputScalar, outputSIMD)); } @@ -406,9 +406,9 @@ TEST_CASE("[Helpers] Linear Ramp unaligned (SIMD vs scalar)") const float start { 0.0f }; std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); - sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, false); sfz::linearRamp(absl::MakeSpan(outputScalar).subspan(1), start, fillValue); - sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); sfz::linearRamp(absl::MakeSpan(outputSIMD).subspan(1), start, fillValue); REQUIRE(approxEqual(outputScalar, outputSIMD)); } @@ -419,7 +419,7 @@ TEST_CASE("[Helpers] Multiplicative Ramp") const float v { fillValue }; std::array output; std::array expected { start, start * v, start * v * v, start * v * v * v, start * v * v * v * v, start * v * v * v * v * v }; - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, false); sfz::multiplicativeRamp(absl::MakeSpan(output), start, v); REQUIRE(approxEqual(output, expected)); } @@ -430,7 +430,7 @@ TEST_CASE("[Helpers] Multiplicative Ramp (SIMD)") const float v { fillValue }; std::array output; std::array expected { start, start * v, start * v * v, start * v * v * v, start * v * v * v * v, start * v * v * v * v * v }; - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, true); sfz::multiplicativeRamp(absl::MakeSpan(output), start, v); REQUIRE(approxEqual(output, expected)); } @@ -440,9 +440,9 @@ TEST_CASE("[Helpers] Multiplicative Ramp (SIMD vs scalar)") const float start { 1.0f }; std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, false); sfz::multiplicativeRamp(absl::MakeSpan(outputScalar), start, fillValue); - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, true); sfz::multiplicativeRamp(absl::MakeSpan(outputSIMD), start, fillValue); REQUIRE(approxEqual(outputScalar, outputSIMD)); } @@ -452,9 +452,9 @@ TEST_CASE("[Helpers] Multiplicative Ramp unaligned (SIMD vs scalar)") const float start { 1.0f }; std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, false); sfz::multiplicativeRamp(absl::MakeSpan(outputScalar).subspan(1), start, fillValue); - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, true); sfz::multiplicativeRamp(absl::MakeSpan(outputSIMD).subspan(1), start, fillValue); REQUIRE(approxEqual(outputScalar, outputSIMD)); } @@ -464,7 +464,7 @@ 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::setSIMDOpStatus(sfz::SIMDOps::add, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::add, false); sfz::add(input, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -474,7 +474,7 @@ 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::setSIMDOpStatus(sfz::SIMDOps::add, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::add, true); sfz::add(input, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -488,9 +488,9 @@ TEST_CASE("[Helpers] Add (SIMD vs scalar)") absl::c_fill(outputScalar, 0.0f); absl::c_fill(outputSIMD, 0.0f); - sfz::setSIMDOpStatus(sfz::SIMDOps::add, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::add, false); sfz::add(input, absl::MakeSpan(outputScalar)); - sfz::setSIMDOpStatus(sfz::SIMDOps::add, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::add, true); sfz::add(input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } @@ -501,7 +501,7 @@ TEST_CASE("[Helpers] MultiplyAdd (Scalar)") std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 5.0f, 4.0f, 3.0f, 2.0f, 1.0f }; std::array expected { 5.0f, 4.2f, 3.6f, 3.2f, 3.0f }; - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -512,7 +512,7 @@ TEST_CASE("[Helpers] MultiplyAdd (SIMD)") std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 5.0f, 4.0f, 3.0f, 2.0f, 1.0f }; std::array expected { 5.0f, 4.2f, 3.6f, 3.2f, 3.0f }; - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -528,9 +528,9 @@ TEST_CASE("[Helpers] MultiplyAdd (SIMD vs scalar)") absl::c_iota(outputScalar, 0.0f); absl::c_iota(outputSIMD, 0.0f); - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); sfz::multiplyAdd(gain, input, absl::MakeSpan(outputScalar)); - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); sfz::multiplyAdd(gain, input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } @@ -541,8 +541,8 @@ TEST_CASE("[Helpers] MultiplyAdd fixed gain (Scalar)") std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 5.0f, 4.0f, 3.0f, 2.0f, 1.0f }; std::array expected { 5.3f, 4.6f, 3.9f, 3.2f, 2.5f }; - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); - sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd1, false); + sfz::multiplyAdd1(gain, input, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -552,8 +552,8 @@ TEST_CASE("[Helpers] MultiplyAdd fixed gain (SIMD)") std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 5.0f, 4.0f, 3.0f, 2.0f, 1.0f }; std::array expected { 5.3f, 4.6f, 3.9f, 3.2f, 2.5f }; - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); - sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd1, true); + sfz::multiplyAdd1(gain, input, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -567,10 +567,10 @@ TEST_CASE("[Helpers] MultiplyAdd fixed gain (SIMD vs scalar)") absl::c_iota(outputScalar, 0.0f); absl::c_iota(outputSIMD, 0.0f); - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); - sfz::multiplyAdd(gain, input, absl::MakeSpan(outputScalar)); - sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); - sfz::multiplyAdd(gain, input, absl::MakeSpan(outputSIMD)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd1, false); + sfz::multiplyAdd1(gain, input, absl::MakeSpan(outputScalar)); + sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd1, true); + sfz::multiplyAdd1(gain, input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } @@ -587,8 +587,8 @@ TEST_CASE("[Helpers] Subtract 2") { std::array output { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array expected { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f }; - sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, false); - sfz::subtract(1.0f, absl::MakeSpan(output)); + sfz::setSIMDOpStatus(sfz::SIMDOps::subtract1, false); + sfz::subtract1(1.0f, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -598,7 +598,7 @@ TEST_CASE("[Helpers] Subtract (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 { 0.0f, -1.0f, -2.0f, -3.0f, -4.0f }; - sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, true); sfz::subtract(input, absl::MakeSpan(output)); REQUIRE(output == expected); } @@ -612,9 +612,9 @@ TEST_CASE("[Helpers] Subtract (SIMD vs scalar)") absl::c_fill(outputScalar, 0.0f); absl::c_fill(outputSIMD, 0.0f); - sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, false); sfz::subtract(input, absl::MakeSpan(outputScalar)); - sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, true); sfz::subtract(input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } @@ -626,10 +626,10 @@ TEST_CASE("[Helpers] Subtract 2 (SIMD vs scalar)") absl::c_iota(outputScalar, 0.0f); absl::c_iota(outputSIMD, 0.0f); - sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, false); - sfz::subtract(1.2f, absl::MakeSpan(outputScalar)); - sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, true); - sfz::subtract(1.2f, absl::MakeSpan(outputSIMD)); + sfz::setSIMDOpStatus(sfz::SIMDOps::subtract1, false); + sfz::subtract1(1.2f, absl::MakeSpan(outputScalar)); + sfz::setSIMDOpStatus(sfz::SIMDOps::subtract1, true); + sfz::subtract1(1.2f, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } @@ -637,7 +637,7 @@ TEST_CASE("[Helpers] copy") { 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 }; - sfz::setSIMDOpStatus(sfz::SIMDOps::copy, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::copy, false); sfz::copy(input, absl::MakeSpan(output)); REQUIRE(output == input); } @@ -646,7 +646,7 @@ TEST_CASE("[Helpers] copy (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 }; - sfz::setSIMDOpStatus(sfz::SIMDOps::copy, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::copy, true); sfz::copy(input, absl::MakeSpan(output)); REQUIRE(output == input); } @@ -660,9 +660,9 @@ TEST_CASE("[Helpers] copy (SIMD vs scalar)") absl::c_fill(outputScalar, 0.0f); absl::c_fill(outputSIMD, 0.0f); - sfz::setSIMDOpStatus(sfz::SIMDOps::copy, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::copy, false); sfz::copy(input, absl::MakeSpan(outputScalar)); - sfz::setSIMDOpStatus(sfz::SIMDOps::copy, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::copy, true); sfz::copy(input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } @@ -670,9 +670,9 @@ TEST_CASE("[Helpers] copy (SIMD vs scalar)") TEST_CASE("[Helpers] Mean") { std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f }; - sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false); REQUIRE(sfz::mean(input) == 5.5f); - sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true); REQUIRE(sfz::mean(input) == 5.5f); } @@ -680,9 +680,9 @@ TEST_CASE("[Helpers] Mean (SIMD vs scalar)") { std::vector input(bigBufferSize); absl::c_iota(input, 0.0f); - sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false); auto scalarResult = sfz::mean(input); - sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true); auto simdResult = sfz::mean(input); REQUIRE( scalarResult == Approx(simdResult).margin(1e-3) ); } @@ -690,9 +690,9 @@ TEST_CASE("[Helpers] Mean (SIMD vs scalar)") TEST_CASE("[Helpers] Mean Squared") { std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f }; - sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); REQUIRE(sfz::meanSquared(input) == 38.5f); - sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); REQUIRE(sfz::meanSquared(input) == 38.5f); } @@ -700,9 +700,9 @@ TEST_CASE("[Helpers] Mean Squared (SIMD vs scalar)") { std::vector input(medBufferSize); absl::c_iota(input, 0.0f); - sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); auto scalarResult = sfz::meanSquared(input); - sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); auto simdResult = sfz::meanSquared(input); REQUIRE( scalarResult == Approx(simdResult).margin(1e-3) ); } @@ -712,7 +712,7 @@ TEST_CASE("[Helpers] Cumulative sum") std::array input { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f }; // 1.1 2.3 3.6 5.0f 6.5 8.1 std::array output; std::array expected { 1.1f, 2.3f, 3.6f, 5.0f, 6.5f, 8.1f }; - sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, false); sfz::cumsum(input, absl::MakeSpan(output)); REQUIRE(approxEqual(output, expected)); } @@ -722,11 +722,11 @@ TEST_CASE("[Helpers] Cumulative sum (SIMD vs Scalar)") std::vector input(bigBufferSize); std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); - sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); sfz::linearRamp(absl::MakeSpan(input), 0.0f, 0.1f); - sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, false); sfz::cumsum(input, absl::MakeSpan(outputScalar)); - sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, true); sfz::cumsum(input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } @@ -736,7 +736,7 @@ 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::setSIMDOpStatus(sfz::SIMDOps::diff, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::diff, false); sfz::diff(input, absl::MakeSpan(output)); REQUIRE(approxEqual(output, expected)); } @@ -746,11 +746,11 @@ TEST_CASE("[Helpers] Diff (SIMD vs Scalar)") std::vector input(bigBufferSize); std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); - sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); sfz::linearRamp(absl::MakeSpan(input), 0.0f, 0.1f); - sfz::setSIMDOpStatus(sfz::SIMDOps::diff, false); + sfz::setSIMDOpStatus(sfz::SIMDOps::diff, false); sfz::diff(input, absl::MakeSpan(outputScalar)); - sfz::setSIMDOpStatus(sfz::SIMDOps::diff, true); + sfz::setSIMDOpStatus(sfz::SIMDOps::diff, true); sfz::diff(input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } From 5dffe248bcb8720fe339fdb7d3c26b8ead8a3abc Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 19 Jun 2020 20:38:53 +0200 Subject: [PATCH 42/42] Remove the unused variable --- src/sfizz/SIMDHelpers.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sfizz/SIMDHelpers.cpp b/src/sfizz/SIMDHelpers.cpp index 7414ede7..c0e21d4e 100644 --- a/src/sfizz/SIMDHelpers.cpp +++ b/src/sfizz/SIMDHelpers.cpp @@ -43,7 +43,6 @@ struct SIMDDispatch { private: std::array(SIMDOps::_sentinel)> simdStatus; - bool initialized { false }; cpuid::cpuinfo info; };