Update the read and write SIMD helpers with the new approach
This commit is contained in:
parent
91435249c0
commit
f827e7c2e5
6 changed files with 168 additions and 175 deletions
|
|
@ -3,6 +3,7 @@ macro(sfizz_add_simd_sources SOURCES_VAR PREFIX)
|
||||||
|
|
||||||
list (APPEND ${SOURCES_VAR}
|
list (APPEND ${SOURCES_VAR}
|
||||||
${PREFIX}/sfizz/SIMDSSE.cpp
|
${PREFIX}/sfizz/SIMDSSE.cpp
|
||||||
|
${PREFIX}/sfizz/SIMDHelpers.cpp
|
||||||
${PREFIX}/sfizz/SIMDNEON.cpp
|
${PREFIX}/sfizz/SIMDNEON.cpp
|
||||||
${PREFIX}/sfizz/SIMDDummy.cpp)
|
${PREFIX}/sfizz/SIMDDummy.cpp)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ void readBaseFile(SndfileHandle& sndFile, sfz::FileAudioBuffer& output, uint32_t
|
||||||
output.clear();
|
output.clear();
|
||||||
sfz::Buffer<float> tempReadBuffer { 2 * numFrames };
|
sfz::Buffer<float> tempReadBuffer { 2 * numFrames };
|
||||||
sndFile.readf(tempReadBuffer.data(), numFrames);
|
sndFile.readf(tempReadBuffer.data(), numFrames);
|
||||||
sfz::readInterleaved<float>(tempReadBuffer, output.getSpan(0), output.getSpan(1));
|
sfz::readInterleaved(tempReadBuffer, output.getSpan(0), output.getSpan(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
|
|
@ -87,7 +87,6 @@ std::unique_ptr<sfz::FileAudioBuffer> readFromFile(SndfileHandle& sndFile, uint3
|
||||||
return outputBuffer;
|
return outputBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void streamFromFile(SndfileHandle& sndFile, uint32_t numFrames, sfz::Oversampling factor, bool reverse, sfz::FileAudioBuffer& output, std::atomic<size_t>* filledFrames = nullptr)
|
void streamFromFile(SndfileHandle& sndFile, uint32_t numFrames, sfz::Oversampling factor, bool reverse, sfz::FileAudioBuffer& output, std::atomic<size_t>* filledFrames = nullptr)
|
||||||
{
|
{
|
||||||
if (factor == sfz::Oversampling::x1) {
|
if (factor == sfz::Oversampling::x1) {
|
||||||
|
|
@ -400,7 +399,7 @@ void sfz::FilePool::loadingThread() noexcept
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto frames = static_cast<uint32_t>(sndFile.frames());
|
const auto frames = static_cast<uint32_t>(sndFile.frames());
|
||||||
streamFromFile<float>(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;
|
promise->dataStatus = FilePromise::DataStatus::Ready;
|
||||||
const auto loadDuration = std::chrono::high_resolution_clock::now() - loadStartTime;
|
const auto loadDuration = std::chrono::high_resolution_clock::now() - loadStartTime;
|
||||||
logger.logFileTime(waitDuration, loadDuration, frames, promise->fileId.filename());
|
logger.logFileTime(waitDuration, loadDuration, frames, promise->fileId.filename());
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,20 @@
|
||||||
#include "SIMDHelpers.h"
|
#include "SIMDHelpers.h"
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include "cpuid/cpuinfo.hpp"
|
||||||
|
|
||||||
namespace sfz{
|
#include "SIMDConfig.h"
|
||||||
|
|
||||||
static std::array<bool, static_cast<unsigned>(sfz::SIMDOps::_sentinel)> simdStatus;
|
#if SFIZZ_HAVE_SSE2
|
||||||
|
#include <xmmintrin.h>
|
||||||
|
#include <emmintrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace sfz {
|
||||||
|
|
||||||
|
static std::array<bool, static_cast<unsigned>(SIMDOps::_sentinel)> simdStatus;
|
||||||
static bool simdStatusInitialized = false;
|
static bool simdStatusInitialized = false;
|
||||||
|
|
||||||
static void resetSIMDStatus()
|
void resetSIMDStatus()
|
||||||
{
|
{
|
||||||
simdStatus[static_cast<unsigned>(SIMDOps::writeInterleaved)] = true;
|
simdStatus[static_cast<unsigned>(SIMDOps::writeInterleaved)] = true;
|
||||||
simdStatus[static_cast<unsigned>(SIMDOps::readInterleaved)] = true;
|
simdStatus[static_cast<unsigned>(SIMDOps::readInterleaved)] = true;
|
||||||
|
|
@ -32,14 +40,15 @@ static void resetSIMDStatus()
|
||||||
simdStatusInitialized = true;
|
simdStatusInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setSIMDOpStatus(SIMDOps op, bool status)
|
void setSIMDOpStatus(SIMDOps op, bool status)
|
||||||
{
|
{
|
||||||
if (!simdStatusInitialized)
|
if (!simdStatusInitialized)
|
||||||
resetSIMDStatus();
|
resetSIMDStatus();
|
||||||
|
|
||||||
simdStatus[static_cast<unsigned>(op)] = status;
|
simdStatus[static_cast<unsigned>(op)] = status;
|
||||||
}
|
}
|
||||||
static bool getSIMDOpStatus(SIMDOps op)
|
|
||||||
|
bool getSIMDOpStatus(SIMDOps op)
|
||||||
{
|
{
|
||||||
if (!simdStatusInitialized)
|
if (!simdStatusInitialized)
|
||||||
resetSIMDStatus();
|
resetSIMDStatus();
|
||||||
|
|
@ -47,5 +56,85 @@ static bool getSIMDOpStatus(SIMDOps op)
|
||||||
return simdStatus[static_cast<unsigned>(op)];
|
return simdStatus[static_cast<unsigned>(op)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr uintptr_t TypeAlignment = 4;
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
inline void tickRead(const T*& input, T*& outputLeft, T*& outputRight)
|
||||||
|
{
|
||||||
|
*outputLeft++ = *input++;
|
||||||
|
*outputRight++ = *input++;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,18 +69,35 @@ enum class SIMDOps {
|
||||||
upsampling,
|
upsampling,
|
||||||
_sentinel //
|
_sentinel //
|
||||||
};
|
};
|
||||||
|
|
||||||
// Enable or disable SIMD accelerators at runtime
|
// Enable or disable SIMD accelerators at runtime
|
||||||
static void setSIMDOpStatus(SIMDOps op, bool status);
|
void setSIMDOpStatus(SIMDOps op, bool status);
|
||||||
static bool getSIMDOpStatus(SIMDOps op);
|
bool getSIMDOpStatus(SIMDOps op);
|
||||||
|
|
||||||
|
constexpr uintptr_t ByteAlignmentMask { config::defaultAlignment - 1 };
|
||||||
|
|
||||||
namespace _internals {
|
template<class T>
|
||||||
template <class T>
|
T* nextAligned(const T* ptr)
|
||||||
inline void snippetRead(const T*& input, T*& outputLeft, T*& outputRight)
|
{
|
||||||
{
|
return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(ptr) + ByteAlignmentMask & (~ByteAlignmentMask));
|
||||||
*outputLeft++ = *input++;
|
}
|
||||||
*outputRight++ = *input++;
|
|
||||||
}
|
template<class T>
|
||||||
|
T* prevAligned(const T* ptr)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(ptr) & (~ByteAlignmentMask));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
bool unaligned(const T* ptr)
|
||||||
|
{
|
||||||
|
return (reinterpret_cast<uintptr_t>(ptr) & ByteAlignmentMask )!= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, class... Args>
|
||||||
|
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.
|
* The output size will be the minimum of the input span and output spans size.
|
||||||
*
|
*
|
||||||
* @tparam T the underlying type
|
* @tparam T the underlying type
|
||||||
* @tparam SIMD use the SIMD version or the scalar version
|
|
||||||
* @param input
|
* @param input
|
||||||
* @param outputLeft
|
* @param outputLeft
|
||||||
* @param outputRight
|
* @param outputRight
|
||||||
*/
|
*/
|
||||||
template <class T, bool SIMD = SIMDConfig::readInterleaved>
|
void readInterleaved(const float* input, float* outputLeft, float* outputRight, unsigned inputSize) noexcept;
|
||||||
void readInterleaved(absl::Span<const T> input, absl::Span<T> outputLeft, absl::Span<T> outputRight) noexcept
|
|
||||||
|
inline void readInterleaved(absl::Span<const float> input, absl::Span<float> outputLeft, absl::Span<float> outputRight) noexcept
|
||||||
{
|
{
|
||||||
// The size of the output is not big enough for the input...
|
// The size of the output is not big enough for the input...
|
||||||
CHECK(outputLeft.size() >= input.size() / 2);
|
CHECK(outputLeft.size() >= input.size() / 2);
|
||||||
CHECK(outputRight.size() >= input.size() / 2);
|
CHECK(outputRight.size() >= input.size() / 2);
|
||||||
|
const auto size = min(input.size(), 2 * outputLeft.size(), 2 * outputRight.size());
|
||||||
auto* in = input.begin();
|
readInterleaved(input.data(), outputLeft.data(), outputRight.data(), size);
|
||||||
auto* lOut = outputLeft.begin();
|
|
||||||
auto* rOut = outputRight.begin();
|
|
||||||
while (in < (input.end() - 1) && lOut < outputLeft.end() && rOut < outputRight.end())
|
|
||||||
_internals::snippetRead<T>(in, lOut, rOut);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace _internals {
|
|
||||||
template <class T>
|
|
||||||
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.
|
* @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.
|
* The output size will be the minimum of the input spans and output span size.
|
||||||
*
|
*
|
||||||
* @tparam T the underlying type
|
* @tparam T the underlying type
|
||||||
* @tparam SIMD use the SIMD version or the scalar version
|
|
||||||
* @param inputLeft
|
* @param inputLeft
|
||||||
* @param inputRight
|
* @param inputRight
|
||||||
* @param output
|
* @param output
|
||||||
*/
|
*/
|
||||||
template <class T, bool SIMD = SIMDConfig::writeInterleaved>
|
void writeInterleaved(const float* inputLeft, const float* inputRight, float* output, unsigned outputSize) noexcept;
|
||||||
void writeInterleaved(absl::Span<const T> inputLeft, absl::Span<const T> inputRight, absl::Span<T> output) noexcept
|
|
||||||
|
inline void writeInterleaved(absl::Span<const float> inputLeft, absl::Span<const float> inputRight, absl::Span<float> output) noexcept
|
||||||
{
|
{
|
||||||
CHECK(inputLeft.size() <= output.size() / 2);
|
// Not enough data in the inputs
|
||||||
CHECK(inputRight.size() <= output.size() / 2);
|
CHECK(inputLeft.size() >= output.size() / 2);
|
||||||
|
CHECK(inputRight.size() >= output.size() / 2);
|
||||||
auto* lIn = inputLeft.begin();
|
const auto size = min(output.size(), 2 * inputLeft.size(), 2 * inputRight.size());
|
||||||
auto* rIn = inputRight.begin();
|
writeInterleaved(inputLeft.data(), inputRight.data(), output.data(), size);
|
||||||
auto* out = output.begin();
|
|
||||||
while (lIn < inputLeft.end() && rIn < inputRight.end() && out < (output.end() - 1))
|
|
||||||
_internals::snippetWrite<T>(out, lIn, rIn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specializations
|
|
||||||
template <>
|
|
||||||
void writeInterleaved<float, true>(absl::Span<const float> inputLeft, absl::Span<const float> inputRight, absl::Span<float> output) noexcept;
|
|
||||||
template <>
|
|
||||||
void readInterleaved<float, true>(absl::Span<const float> input, absl::Span<float> outputLeft, absl::Span<float> outputRight) noexcept;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Fill a buffer with a value; comparable to std::fill in essence.
|
* @brief Fill a buffer with a value; comparable to std::fill in essence.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -12,116 +12,9 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <xmmintrin.h>
|
#include <xmmintrin.h>
|
||||||
#include <emmintrin.h>
|
#include <emmintrin.h>
|
||||||
|
|
||||||
#include "mathfuns/sse_mathfun.h"
|
#include "mathfuns/sse_mathfun.h"
|
||||||
|
|
||||||
using Type = float;
|
constexpr uintptr_t TypeAlignment = 4;
|
||||||
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<float*>((reinterpret_cast<uintptr_t>(ptr) + ByteAlignmentMask) & (~ByteAlignmentMask));
|
|
||||||
}
|
|
||||||
|
|
||||||
float* prevAligned(const float* ptr)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<float*>(reinterpret_cast<uintptr_t>(ptr) & (~ByteAlignmentMask));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool unaligned(const float* ptr)
|
|
||||||
{
|
|
||||||
return (reinterpret_cast<uintptr_t>(ptr) & ByteAlignmentMask) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class... Args>
|
|
||||||
bool unaligned(const float* ptr1, Args... rest)
|
|
||||||
{
|
|
||||||
return unaligned(ptr1) || unaligned(rest...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
void sfz::readInterleaved<float, true>(absl::Span<const float> input, absl::Span<float> outputLeft, absl::Span<float> 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<float>(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<float>(in, lOut, rOut);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
void sfz::writeInterleaved<float, true>(absl::Span<const float> inputLeft, absl::Span<const float> inputRight, absl::Span<float> 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<float>(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<float>(out, lIn, rIn);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void sfz::fill<float, true>(absl::Span<float> output, float value) noexcept
|
void sfz::fill<float, true>(absl::Span<float> output, float value) noexcept
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,8 @@ TEST_CASE("[Helpers] Interleaved read")
|
||||||
std::array<float, 16> 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<float, 16> 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<float, 8> leftOutput;
|
std::array<float, 8> leftOutput;
|
||||||
std::array<float, 8> rightOutput;
|
std::array<float, 8> rightOutput;
|
||||||
sfz::readInterleaved<float, false>(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false);
|
||||||
|
sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||||
std::array<float, 16> real;
|
std::array<float, 16> real;
|
||||||
|
|
||||||
auto realIdx = 0;
|
auto realIdx = 0;
|
||||||
|
|
@ -139,7 +140,8 @@ TEST_CASE("[Helpers] Interleaved read unaligned end")
|
||||||
std::array<float, 20> 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<float, 20> 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<float, 10> leftOutput;
|
std::array<float, 10> leftOutput;
|
||||||
std::array<float, 10> rightOutput;
|
std::array<float, 10> rightOutput;
|
||||||
sfz::readInterleaved<float, false>(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false);
|
||||||
|
sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||||
std::array<float, 20> real;
|
std::array<float, 20> real;
|
||||||
|
|
||||||
auto realIdx = 0;
|
auto realIdx = 0;
|
||||||
|
|
@ -156,7 +158,8 @@ TEST_CASE("[Helpers] Small interleaved read unaligned end")
|
||||||
std::array<float, 6> expected { 0.0f, 1.0f, 2.0f, 10.0f, 11.0f, 12.0f };
|
std::array<float, 6> expected { 0.0f, 1.0f, 2.0f, 10.0f, 11.0f, 12.0f };
|
||||||
std::array<float, 3> leftOutput;
|
std::array<float, 3> leftOutput;
|
||||||
std::array<float, 3> rightOutput;
|
std::array<float, 3> rightOutput;
|
||||||
sfz::readInterleaved<float, false>(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false);
|
||||||
|
sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||||
std::array<float, 6> real;
|
std::array<float, 6> real;
|
||||||
|
|
||||||
auto realIdx = 0;
|
auto realIdx = 0;
|
||||||
|
|
@ -173,7 +176,8 @@ TEST_CASE("[Helpers] Interleaved read -- SIMD")
|
||||||
std::array<float, 16> 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<float, 16> 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<float, 8> leftOutput;
|
std::array<float, 8> leftOutput;
|
||||||
std::array<float, 8> rightOutput;
|
std::array<float, 8> rightOutput;
|
||||||
sfz::readInterleaved<float, true>(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true);
|
||||||
|
sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||||
std::array<float, 16> real;
|
std::array<float, 16> real;
|
||||||
|
|
||||||
auto realIdx = 0;
|
auto realIdx = 0;
|
||||||
|
|
@ -190,7 +194,8 @@ TEST_CASE("[Helpers] Interleaved read unaligned end -- SIMD")
|
||||||
std::array<float, 20> 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<float, 20> 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<float, 10> leftOutput;
|
std::array<float, 10> leftOutput;
|
||||||
std::array<float, 10> rightOutput;
|
std::array<float, 10> rightOutput;
|
||||||
sfz::readInterleaved<float, true>(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true);
|
||||||
|
sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||||
std::array<float, 20> real;
|
std::array<float, 20> real;
|
||||||
|
|
||||||
auto realIdx = 0;
|
auto realIdx = 0;
|
||||||
|
|
@ -207,7 +212,8 @@ TEST_CASE("[Helpers] Small interleaved read unaligned end -- SIMD")
|
||||||
std::array<float, 6> expected { 0.0f, 1.0f, 2.0f, 10.0f, 11.0f, 12.0f };
|
std::array<float, 6> expected { 0.0f, 1.0f, 2.0f, 10.0f, 11.0f, 12.0f };
|
||||||
std::array<float, 3> leftOutput;
|
std::array<float, 3> leftOutput;
|
||||||
std::array<float, 3> rightOutput;
|
std::array<float, 3> rightOutput;
|
||||||
sfz::readInterleaved<float, true>(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true);
|
||||||
|
sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||||
std::array<float, 6> real;
|
std::array<float, 6> real;
|
||||||
|
|
||||||
auto realIdx = 0;
|
auto realIdx = 0;
|
||||||
|
|
@ -226,8 +232,10 @@ TEST_CASE("[Helpers] Interleaved read SIMD vs Scalar")
|
||||||
std::array<float, medBufferSize> leftOutputSIMD;
|
std::array<float, medBufferSize> leftOutputSIMD;
|
||||||
std::array<float, medBufferSize> rightOutputSIMD;
|
std::array<float, medBufferSize> rightOutputSIMD;
|
||||||
std::iota(input.begin(), input.end(), 0.0f);
|
std::iota(input.begin(), input.end(), 0.0f);
|
||||||
sfz::readInterleaved<float, false>(input, absl::MakeSpan(leftOutputScalar), absl::MakeSpan(rightOutputScalar));
|
sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false);
|
||||||
sfz::readInterleaved<float, true>(input, absl::MakeSpan(leftOutputSIMD), absl::MakeSpan(rightOutputSIMD));
|
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(leftOutputScalar == leftOutputSIMD);
|
||||||
REQUIRE(rightOutputScalar == rightOutputSIMD);
|
REQUIRE(rightOutputScalar == rightOutputSIMD);
|
||||||
}
|
}
|
||||||
|
|
@ -247,7 +255,8 @@ TEST_CASE("[Helpers] Interleaved write")
|
||||||
std::array<float, 8> rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f };
|
std::array<float, 8> rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f };
|
||||||
std::array<float, 16> output;
|
std::array<float, 16> output;
|
||||||
std::array<float, 16> 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 };
|
std::array<float, 16> 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<float, false>(leftInput, rightInput, absl::MakeSpan(output));
|
sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false);
|
||||||
|
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output));
|
||||||
REQUIRE(output == expected);
|
REQUIRE(output == expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -257,7 +266,8 @@ TEST_CASE("[Helpers] Interleaved write unaligned end")
|
||||||
std::array<float, 10> rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f };
|
std::array<float, 10> rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f };
|
||||||
std::array<float, 20> output;
|
std::array<float, 20> output;
|
||||||
std::array<float, 20> 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 };
|
std::array<float, 20> 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<float, false>(leftInput, rightInput, absl::MakeSpan(output));
|
sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false);
|
||||||
|
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output));
|
||||||
REQUIRE(output == expected);
|
REQUIRE(output == expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -267,7 +277,8 @@ TEST_CASE("[Helpers] Small interleaved write unaligned end")
|
||||||
std::array<float, 3> rightInput { 10.0f, 11.0f, 12.0f };
|
std::array<float, 3> rightInput { 10.0f, 11.0f, 12.0f };
|
||||||
std::array<float, 6> output;
|
std::array<float, 6> output;
|
||||||
std::array<float, 6> expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f };
|
std::array<float, 6> expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f };
|
||||||
sfz::writeInterleaved<float, false>(leftInput, rightInput, absl::MakeSpan(output));
|
sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false);
|
||||||
|
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output));
|
||||||
REQUIRE(output == expected);
|
REQUIRE(output == expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -286,7 +297,8 @@ TEST_CASE("[Helpers] Interleaved write -- SIMD")
|
||||||
std::array<float, 8> rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f };
|
std::array<float, 8> rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f };
|
||||||
std::array<float, 16> output;
|
std::array<float, 16> output;
|
||||||
std::array<float, 16> 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 };
|
std::array<float, 16> 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<float, true>(leftInput, rightInput, absl::MakeSpan(output));
|
sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true);
|
||||||
|
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output));
|
||||||
REQUIRE(output == expected);
|
REQUIRE(output == expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -296,7 +308,7 @@ TEST_CASE("[Helpers] Interleaved write unaligned end -- SIMD")
|
||||||
std::array<float, 10> rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f };
|
std::array<float, 10> rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f };
|
||||||
std::array<float, 20> output;
|
std::array<float, 20> output;
|
||||||
std::array<float, 20> 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 };
|
std::array<float, 20> 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<float, true>(leftInput, rightInput, absl::MakeSpan(output));
|
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output));
|
||||||
REQUIRE(output == expected);
|
REQUIRE(output == expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -306,7 +318,8 @@ TEST_CASE("[Helpers] Small interleaved write unaligned end -- SIMD")
|
||||||
std::array<float, 3> rightInput { 10.0f, 11.0f, 12.0f };
|
std::array<float, 3> rightInput { 10.0f, 11.0f, 12.0f };
|
||||||
std::array<float, 6> output;
|
std::array<float, 6> output;
|
||||||
std::array<float, 6> expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f };
|
std::array<float, 6> expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f };
|
||||||
sfz::writeInterleaved<float, true>(leftInput, rightInput, absl::MakeSpan(output));
|
sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true);
|
||||||
|
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output));
|
||||||
REQUIRE(output == expected);
|
REQUIRE(output == expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -318,8 +331,10 @@ TEST_CASE("[Helpers] Interleaved write SIMD vs Scalar")
|
||||||
std::array<float, medBufferSize * 2> outputSIMD;
|
std::array<float, medBufferSize * 2> outputSIMD;
|
||||||
std::iota(leftInput.begin(), leftInput.end(), 0.0f);
|
std::iota(leftInput.begin(), leftInput.end(), 0.0f);
|
||||||
std::iota(rightInput.begin(), rightInput.end(), static_cast<float>(medBufferSize));
|
std::iota(rightInput.begin(), rightInput.end(), static_cast<float>(medBufferSize));
|
||||||
sfz::writeInterleaved<float, false>(leftInput, rightInput, absl::MakeSpan(outputScalar));
|
sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false);
|
||||||
sfz::writeInterleaved<float, true>(leftInput, rightInput, absl::MakeSpan(outputSIMD));
|
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(outputScalar));
|
||||||
|
sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true);
|
||||||
|
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(outputSIMD));
|
||||||
REQUIRE(outputScalar == outputSIMD);
|
REQUIRE(outputScalar == outputSIMD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue