diff --git a/cmake/CheckIPO.cmake b/cmake/CheckIPO.cmake index d25c1f10..c86d3c04 100644 --- a/cmake/CheckIPO.cmake +++ b/cmake/CheckIPO.cmake @@ -2,6 +2,10 @@ include (CheckIPOSupported) check_ipo_supported (RESULT result OUTPUT output) +if (CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l) + set(ENABLE_LTO OFF) +endif() + if (result AND ENABLE_LTO AND CMAKE_BUILD_TYPE STREQUAL "Release") message (STATUS "\nLTO enabled.") else() diff --git a/cmake/SfizzSIMDSourceFilesCheck.cmake b/cmake/SfizzSIMDSourceFilesCheck.cmake index 1237b3bc..188159fc 100644 --- a/cmake/SfizzSIMDSourceFilesCheck.cmake +++ b/cmake/SfizzSIMDSourceFilesCheck.cmake @@ -4,7 +4,7 @@ CHECK_INCLUDE_FILES(x86intrin.h HAVE_X86INTRIN_H) CHECK_INCLUDE_FILES(intrin.h HAVE_INTRIN_H) if (!APPLE) - CHECK_INCLUDE_FILES (arm_neon.h HAVE_ARM_NEON_H) +CHECK_INCLUDE_FILES (arm_neon.h HAVE_ARM_NEON_H) endif() # SIMD checks @@ -14,13 +14,12 @@ if (HAVE_X86INTRIN_H AND UNIX) elseif (HAVE_INTRIN_H AND WIN32) add_compile_options (/DHAVE_INTRIN_H) set (SFIZZ_SIMD_SOURCES sfizz/SIMDSSE.cpp) -elseif (HAVE_ARM_NEON_H AND UNIX) +elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l") add_compile_options (-DHAVE_ARM_NEON_H) - add_compile_options (-mfpu=neon-fp-armv8) + add_compile_options (-mfpu=neon) add_compile_options (-march=native) add_compile_options (-mtune=cortex-a53) - add_compile_options (-funsafe-math-optimizations) - set (SFIZZ_SIMD_SOURCES sfizz/SIMDDummy.cpp) + set (SFIZZ_SIMD_SOURCES sfizz/SIMDNEON.cpp) else() set (SFIZZ_SIMD_SOURCES sfizz/SIMDDummy.cpp) endif() diff --git a/src/sfizz/SIMDNEON.cpp b/src/sfizz/SIMDNEON.cpp new file mode 100644 index 00000000..c3321944 --- /dev/null +++ b/src/sfizz/SIMDNEON.cpp @@ -0,0 +1,236 @@ +// 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 +#include "SIMDHelpers.h" + +using Type = float; +[[maybe_unused]] constexpr uintptr_t TypeAlignment { 4 }; +[[maybe_unused]] constexpr uintptr_t TypeAlignmentMask { TypeAlignment - 1 }; +[[maybe_unused]] constexpr uintptr_t ByteAlignment { TypeAlignment * sizeof(Type) }; +[[maybe_unused]] 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 leftCoeffs, absl::Span rightCoeffs) noexcept +{ + sfzInterpolationCast(floatJumps, jumps, leftCoeffs, rightCoeffs); +} + +template <> +void sfz::diff(absl::Span input, absl::Span output) noexcept +{ + diff(input, output); +} diff --git a/src/sfizz/ScopedFTZ.cpp b/src/sfizz/ScopedFTZ.cpp index 47992580..19bf35c1 100644 --- a/src/sfizz/ScopedFTZ.cpp +++ b/src/sfizz/ScopedFTZ.cpp @@ -51,6 +51,6 @@ ScopedFTZ::~ScopedFTZ() #if (HAVE_X86INTRIN_H || HAVE_INTRIN_H) _mm_setcsr(registerState); #elif HAVE_ARM_NEON_H - asm volatile("vmsr %0, fpscr" : : "ri"(registerState)); + asm volatile("vmrs %0, fpscr" : : "ri"(registerState)); #endif }