Browse Source

Fix correctness bugs/typos in simd library. Add log10, sgn, andnot, and ifelse to simd.

tags/v1.0.0
Andrew Belt 5 years ago
parent
commit
4612052e04
3 changed files with 75 additions and 29 deletions
  1. +34
    -17
      include/dsp/common.hpp
  2. +14
    -0
      include/simd/functions.hpp
  3. +27
    -12
      include/simd/vector.hpp

+ 34
- 17
include/dsp/common.hpp View File

@@ -1,5 +1,6 @@
#pragma once
#include "math.hpp"
#include "simd/functions.hpp"


namespace rack {
@@ -27,44 +28,60 @@ inline float sinc(float x) {
return std::sin(x) / x;
}

template <typename T>
T sinc(T x) {
T zeromask = (x == 0.f);
x *= M_PI;
x = simd::sin(x) / x;
return simd::ifelse(zeromask, 1.f, x);
}

// Conversion functions

inline float amplitudeToDb(float amp) {
return std::log10(amp) * 20.f;
template <typename T>
T amplitudeToDb(T amp) {
return simd::log10(amp) * 20;
}

inline float dbToAmplitude(float db) {
return std::pow(10.f, db / 20.f);
template <typename T>
T dbToAmplitude(T db) {
return std::pow(10, db / 20);
}

// Functions for parameter scaling

inline float quadraticBipolar(float x) {
float x2 = x*x;
return (x >= 0.f) ? x2 : -x2;
template <typename T>
T quadraticBipolar(T x) {
return simd::sgn(x) * (x*x);
}

inline float cubic(float x) {
template <typename T>
T cubic(T x) {
return x*x*x;
}

inline float quarticBipolar(float x) {
float y = x*x*x*x;
return (x >= 0.f) ? y : -y;
template <typename T>
T quarticBipolar(T x) {
return simd::sgn(x) * (x*x*x*x);
}

inline float quintic(float x) {
template <typename T>
T quintic(T x) {
// optimal with -fassociative-math
return x*x*x*x*x;
}

inline float sqrtBipolar(float x) {
return (x >= 0.f) ? std::sqrt(x) : -std::sqrt(-x);
template <typename T>
T sqrtBipolar(T x) {
return simd::sgn(x) * simd::sqrt(x);
}

/** This is pretty much a scaled sinh */
inline float exponentialBipolar(float b, float x) {
const float a = b - 1.f / b;
/** This is pretty much a scaled sinh.
Slow. Not recommended for parameter scaling.
*/
template <typename T>
T exponentialBipolar(T b, T x) {
T a = b - 1.f / b;
return (std::pow(b, x) - std::pow(b, -x)) / a;
}



+ 14
- 0
include/simd/functions.hpp View File

@@ -46,6 +46,12 @@ inline f32_4 log(f32_4 x) {
return f32_4(sse_mathfun_log_ps(x.v));
}

using std::log10;

inline f32_4 log10(f32_4 x) {
return f32_4(sse_mathfun_log_ps(x.v)) / std::log(10.f);
}

using std::exp;

inline f32_4 exp(f32_4 x) {
@@ -140,6 +146,14 @@ inline f32_4 rescale(f32_4 x, f32_4 xMin, f32_4 xMax, f32_4 yMin, f32_4 yMax) {
return yMin + (x - xMin) / (xMax - xMin) * (yMax - yMin);
}

using math::sgn;

inline f32_4 sgn(f32_4 x) {
f32_4 signbit = x & -0.f;
f32_4 nonzero = (x != 0.f);
return signbit | (nonzero & 1.f);
}


} // namespace simd
} // namespace rack

+ 27
- 12
include/simd/vector.hpp View File

@@ -1,6 +1,7 @@
#pragma once
#include <cstring>
#include <x86intrin.h>
#include <type_traits>


namespace rack {
@@ -106,8 +107,8 @@ DECLARE_F32_4_OPERATOR_INFIX(operator-, _mm_sub_ps)
DECLARE_F32_4_OPERATOR_INFIX(operator*, _mm_mul_ps)
DECLARE_F32_4_OPERATOR_INFIX(operator/, _mm_div_ps)

/**
Use these to apply logic, bit masks, and conditions to elements.
/* Use these to apply logic, bit masks, and conditions to elements.
Boolean operators on vectors give 0x00000000 for false and 0xffffffff for true, for each vector element.

Examples:

@@ -117,10 +118,8 @@ Subtract 1 from value if greater than or equal to 1.
*/
DECLARE_F32_4_OPERATOR_INFIX(operator^, _mm_xor_ps)
DECLARE_F32_4_OPERATOR_INFIX(operator&, _mm_and_ps)
DECLARE_F32_4_OPERATOR_INFIX(operator|, _mm_mul_ps)
DECLARE_F32_4_OPERATOR_INFIX(operator|, _mm_or_ps)

/** Boolean operators on vectors give 0x00000000 for false and 0xffffffff for true, for each vector element.
*/
DECLARE_F32_4_OPERATOR_INCREMENT(operator+=, operator+);
DECLARE_F32_4_OPERATOR_INCREMENT(operator-=, operator-);
DECLARE_F32_4_OPERATOR_INCREMENT(operator*=, operator*);
@@ -129,6 +128,13 @@ DECLARE_F32_4_OPERATOR_INCREMENT(operator^=, operator^);
DECLARE_F32_4_OPERATOR_INCREMENT(operator&=, operator&);
DECLARE_F32_4_OPERATOR_INCREMENT(operator|=, operator|);

DECLARE_F32_4_OPERATOR_INFIX(operator==, _mm_cmpeq_ps)
DECLARE_F32_4_OPERATOR_INFIX(operator>=, _mm_cmpge_ps)
DECLARE_F32_4_OPERATOR_INFIX(operator>, _mm_cmpgt_ps)
DECLARE_F32_4_OPERATOR_INFIX(operator<=, _mm_cmple_ps)
DECLARE_F32_4_OPERATOR_INFIX(operator<, _mm_cmplt_ps)
DECLARE_F32_4_OPERATOR_INFIX(operator!=, _mm_cmpneq_ps)

/** `+a` */
inline f32_4 operator+(const f32_4 &a) {
return a;
@@ -167,15 +173,24 @@ inline f32_4 operator--(f32_4 &a, int) {

/** `~a` */
inline f32_4 operator~(const f32_4 &a) {
return f32_4(_mm_xor_ps(a.v, _mm_cmpeq_ps(a.v, a.v)));
f32_4 mask = f32_4::zero();
mask = (mask == mask);
return a ^ mask;
}

DECLARE_F32_4_OPERATOR_INFIX(operator==, _mm_cmpeq_ps)
DECLARE_F32_4_OPERATOR_INFIX(operator>=, _mm_cmpge_ps)
DECLARE_F32_4_OPERATOR_INFIX(operator>, _mm_cmpgt_ps)
DECLARE_F32_4_OPERATOR_INFIX(operator<=, _mm_cmple_ps)
DECLARE_F32_4_OPERATOR_INFIX(operator<, _mm_cmplt_ps)
DECLARE_F32_4_OPERATOR_INFIX(operator!=, _mm_cmpneq_ps)

// helpful idioms


/** `~a & b` */
inline f32_4 andnot(const f32_4 &a, const f32_4 &b) {
return f32_4(_mm_andnot_ps(a.v, b.v));
}

/** Given a mask, returns a if mask is 0xffffffff per element, b if mask is 0x00000000 */
inline f32_4 ifelse(const f32_4 &mask, const f32_4 &a, const f32_4 &b) {
return (a & mask) | andnot(mask, b);
}


} // namespace simd


Loading…
Cancel
Save