From 2806b29982760231fc50105e61d1599ef5f8c0cb Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sat, 30 Nov 2019 08:33:22 +0100 Subject: [PATCH] Document SIMD helpers --- src/sfizz/SIMDHelpers.h | 273 +++++++++++++++++++++++++++++++++------- 1 file changed, 230 insertions(+), 43 deletions(-) diff --git a/src/sfizz/SIMDHelpers.h b/src/sfizz/SIMDHelpers.h index dcb21eb6..33b8c8ab 100644 --- a/src/sfizz/SIMDHelpers.h +++ b/src/sfizz/SIMDHelpers.h @@ -22,37 +22,37 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** - * @file SIMDHelpers.h + * @file SIMDHelpers.h * @author Paul Ferrand (paul@ferrand.cc) * @brief This file contains useful functions to treat buffers of numerical values - * (e.g. a buffer of floats usually). - * + * (e.g. a buffer of floats usually). + * * 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 + * + * 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. - * + * * 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 * and deactivate each SIMD specialization with a fine granularity, since SIMD performance * will be very dependent on the processor architecture. Modern processors can also organize their * instructions so that scalar non-SIMD code runs sometimes much more efficiently than SIMD code * especially when the latter does not operate on misaligned buffers. - * + * * @version 0.1 * @date 2019-11-23 - * + * * @copyright Copyright (c) 2019 - * + * */ #pragma once #include "Config.h" @@ -74,14 +74,14 @@ namespace _internals { /** * @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 * @tparam SIMD use the SIMD version or the scalar version - * @param input + * @param input * @param outputLeft - * @param outputRight + * @param outputRight */ template void readInterleaved(absl::Span input, absl::Span outputLeft, absl::Span outputRight) noexcept @@ -108,14 +108,14 @@ namespace _internals { /** * @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 * @tparam SIMD use the SIMD version or the scalar version - * @param inputLeft - * @param inputRight - * @param output + * @param inputLeft + * @param inputRight + * @param output */ template void writeInterleaved(absl::Span inputLeft, absl::Span inputRight, absl::Span output) noexcept @@ -138,11 +138,11 @@ void readInterleaved(absl::Span input, absl::Span void fill(absl::Span output, T value) noexcept @@ -155,11 +155,11 @@ void fill(absl::Span output, float value) noexcept; /** * @brief Exp math function - * + * * @tparam T the underlying type * @tparam SIMD use the SIMD version or the scalar version - * @param input - * @param output + * @param input + * @param output */ template void exp(absl::Span input, absl::Span output) noexcept @@ -175,13 +175,13 @@ void exp(absl::Span input, absl::Span output) n /** * @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 + * @param input + * @param output */ template void log(absl::Span input, absl::Span output) noexcept @@ -197,13 +197,13 @@ void log(absl::Span input, absl::Span output) n /** * @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 + * @param input + * @param output */ template void sin(absl::Span input, absl::Span output) noexcept @@ -219,13 +219,13 @@ void sin(absl::Span input, absl::Span output) n /** * @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 + * @param input + * @param output */ template void cos(absl::Span input, absl::Span output) noexcept @@ -264,21 +264,22 @@ namespace _internals { /** * @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. - * + * 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 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 + * @return float */ template float saturatingSFZIndex(absl::Span jumps, absl::Span leftCoeffs, absl::Span rightCoeffs, absl::Span indices, T floatIndex, T loopEnd) noexcept @@ -319,6 +320,23 @@ namespace _internals { } } +/** + * @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 { @@ -349,6 +367,17 @@ namespace _internals { } } +/** + * @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 + */ template void applyGain(T gain, absl::Span input, absl::Span output) noexcept { @@ -368,6 +397,17 @@ namespace _internals { } } +/** + * @brief Applies a vector gain to an input stap + * + * The output size will be the minimum of the gain, input span and output span size. + * + * @tparam T the underlying type + * @tparam SIMD use the SIMD version or the scalar version + * @param gain + * @param input + * @param output + */ template void applyGain(absl::Span gain, absl::Span input, absl::Span output) noexcept { @@ -381,12 +421,30 @@ void applyGain(absl::Span gain, absl::Span input, absl::Span(g, in, out); } +/** + * @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 { applyGain(gain, output, 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 + */ template void applyGain(absl::Span gain, absl::Span output) noexcept { @@ -407,6 +465,17 @@ namespace _internals { } } +/** + * @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 + */ template void multiplyAdd(absl::Span gain, absl::Span input, absl::Span output) noexcept { @@ -432,6 +501,16 @@ namespace _internals { } } +/** + * @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 + * @return T + */ template T linearRamp(absl::Span output, T start, T step) noexcept { @@ -450,6 +529,16 @@ 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 { @@ -478,6 +567,16 @@ namespace _internals { } } +/** + * @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 + */ template void add(absl::Span input, absl::Span output) noexcept { @@ -518,6 +617,14 @@ namespace _internals { } } +/** + * @brief Subtract a value from a 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 { @@ -527,6 +634,16 @@ void subtract(const T value, absl::Span output) noexcept _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 + */ template void subtract(absl::Span input, absl::Span output) noexcept { @@ -552,6 +669,16 @@ namespace _internals { } } +/** + * @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 + */ template void copy(absl::Span input, absl::Span output) noexcept { @@ -576,6 +703,17 @@ namespace _internals { } } +/** + * @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 { @@ -592,6 +730,14 @@ void pan(absl::Span panEnvelope, absl::Span leftBuffer, absl::Span void pan(absl::Span panEnvelope, absl::Span leftBuffer, absl::Span rightBuffer) noexcept; +/** + * @brief Computes the mean of a span + * + * @tparam T the underlying type + * @tparam SIMD use the SIMD version or the scalar version + * @param vector + * @return T + */ template T mean(absl::Span vector) noexcept { @@ -609,6 +755,14 @@ T mean(absl::Span vector) noexcept template <> float mean(absl::Span vector) noexcept; +/** + * @brief Computes the mean squared of a span + * + * @tparam T the underlying type + * @tparam SIMD use the SIMD version or the scalar version + * @param vector + * @return T + */ template T meanSquared(absl::Span vector) noexcept { @@ -637,6 +791,17 @@ namespace _internals { } } +/** + * @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 + * @tparam SIMD use the SIMD version or the scalar version + * @param vector + * @return T + */ template void cumsum(absl::Span input, absl::Span output) noexcept { @@ -670,6 +835,17 @@ namespace _internals { } } +/** + * @brief Computes the linear interpolation coefficients for a floating point index + * 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 void sfzInterpolationCast(absl::Span floatJumps, absl::Span jumps, absl::Span leftCoeffs, absl::Span rightCoeffs) noexcept { @@ -700,6 +876,17 @@ namespace _internals { } } +/** + * @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 + */ template void diff(absl::Span input, absl::Span output) noexcept { @@ -719,4 +906,4 @@ void diff(absl::Span input, absl::Span output) noexcept template <> void diff(absl::Span input, absl::Span output) noexcept; -} // namespace sfz \ No newline at end of file +} // namespace sfz