From 852b9845528e77e7ccce5de46de73d58c6859158 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 10 Dec 2018 21:28:29 -0500 Subject: [PATCH] refactored for different machines, sgemv_accum16 using NEON intrisics Signed-off-by: Jean-Marc Valin --- src/nnet.c | 345 +------------------------------------------------ src/vec.h | 173 +++++++++++++++++++++++++ src/vec_avx.h | 219 +++++++++++++++++++++++++++++++ src/vec_neon.h | 194 +++++++++++++++++++++++++++ 4 files changed, 590 insertions(+), 341 deletions(-) create mode 100644 src/vec.h create mode 100644 src/vec_avx.h create mode 100644 src/vec_neon.h diff --git a/src/nnet.c b/src/nnet.c index e2735ae..0e2c10c 100644 --- a/src/nnet.c +++ b/src/nnet.c @@ -42,350 +42,13 @@ #define SOFTMAX_HACK #ifdef __AVX__ -#include - - -#ifdef __AVX2__ -static __m256 exp8_approx(__m256 X) -{ - const __m256 K0 = _mm256_set1_ps(0.99992522f); - const __m256 K1 = _mm256_set1_ps(0.69583354f); - const __m256 K2 = _mm256_set1_ps(0.22606716f); - const __m256 K3 = _mm256_set1_ps(0.078024523f); - const __m256 log2_E = _mm256_set1_ps(1.44269504); - const __m256 max_in = _mm256_set1_ps(50.f); - const __m256 min_in = _mm256_set1_ps(-50.f); - const __m256i mask = _mm256_set1_epi32(0x7fffffff); - __m256 XF, Y; - __m256i I; - X = _mm256_mul_ps(X, log2_E); - X = _mm256_max_ps(min_in, _mm256_min_ps(max_in, X)); - XF = _mm256_floor_ps(X); - I = _mm256_cvtps_epi32(XF); - X = _mm256_sub_ps(X, XF); - Y = _mm256_fmadd_ps(_mm256_fmadd_ps(_mm256_fmadd_ps(K3, X, K2), X, K1), X, K0); - I = _mm256_slli_epi32(I, 23); - Y = _mm256_castsi256_ps(_mm256_and_si256(mask, _mm256_add_epi32(I, _mm256_castps_si256(Y)))); - return Y; -} +#include "vec_avx.h" +#elif __ARM_NEON__ +#include "vec_neon.h" #else -#define _mm256_fmadd_ps(a,b,c) _mm256_add_ps(_mm256_mul_ps(a, b), c) -#define _mm_fmadd_ps(a,b,c) _mm_add_ps(_mm_mul_ps(a, b), c) -static __m128 exp4_approx(__m128 X) -{ - const __m128 K0 = _mm_set1_ps(0.99992522f); - const __m128 K1 = _mm_set1_ps(0.69583354f); - const __m128 K2 = _mm_set1_ps(0.22606716f); - const __m128 K3 = _mm_set1_ps(0.078024523f); - const __m128 log2_E = _mm_set1_ps(1.44269504); - const __m128 max_in = _mm_set1_ps(50.f); - const __m128 min_in = _mm_set1_ps(-50.f); - const __m128i mask = _mm_set1_epi32(0x7fffffff); - __m128 XF, Y; - __m128i I; - X = _mm_mul_ps(X, log2_E); - X = _mm_max_ps(min_in, _mm_min_ps(max_in, X)); - XF = _mm_floor_ps(X); - I = _mm_cvtps_epi32(XF); - X = _mm_sub_ps(X, XF); - Y = _mm_fmadd_ps(_mm_fmadd_ps(_mm_fmadd_ps(K3, X, K2), X, K1), X, K0); - I = _mm_slli_epi32(I, 23); - Y = _mm_castsi128_ps(_mm_and_si128(mask, _mm_add_epi32(I, _mm_castps_si128(Y)))); - return Y; -} -static __m256 exp8_approx(__m256 X) -{ - __m256 Y; - __m128 Xhi, Xlo, Yhi, Ylo; - Xhi = _mm256_extractf128_ps(X, 1); - Xlo = _mm256_extractf128_ps(X, 0); - Yhi = exp4_approx(Xhi); - Ylo = exp4_approx(Xlo); - Y = _mm256_insertf128_ps(_mm256_setzero_ps(), Yhi, 1); - Y = _mm256_insertf128_ps(Y, Ylo, 0); - return Y; -} -#endif - -static float celt_exp(float x) -{ - float out[8]; - __m256 X, Y; - X = _mm256_set1_ps(x); - Y = exp8_approx(X); - _mm256_storeu_ps(out, Y); - return out[0]; -} - -static void softmax(float *y, const float *x, int N) -{ - int i; - for (i=0;i-8)) - return -1; -#ifndef FIXED_POINT - /* Another check in case of -ffast-math */ - if (celt_isnan(x)) - return 0; +#include "vec.h" #endif - if (x<0) - { - x=-x; - sign=-1; - } - i = (int)floor(.5f+25*x); - x -= .04f*i; - y = tansig_table[i]; - dy = 1-y*y; - y = y + x*dy*(1 - y*x); - return sign*y; -} - -static OPUS_INLINE float sigmoid_approx(float x) -{ - return .5f + .5f*tansig_approx(.5f*x); -} - -static void softmax(float *y, const float *x, int N) -{ - int i; - for (i=0;i-8)) + return -1; +#ifndef FIXED_POINT + /* Another check in case of -ffast-math */ + if (celt_isnan(x)) + return 0; +#endif + if (x<0) + { + x=-x; + sign=-1; + } + i = (int)floor(.5f+25*x); + x -= .04f*i; + y = tansig_table[i]; + dy = 1-y*y; + y = y + x*dy*(1 - y*x); + return sign*y; +} + +static OPUS_INLINE float sigmoid_approx(float x) +{ + return .5f + .5f*tansig_approx(.5f*x); +} + +static void softmax(float *y, const float *x, int N) +{ + int i; + for (i=0;i + +#ifdef __AVX2__ +static __m256 exp8_approx(__m256 X) +{ + const __m256 K0 = _mm256_set1_ps(0.99992522f); + const __m256 K1 = _mm256_set1_ps(0.69583354f); + const __m256 K2 = _mm256_set1_ps(0.22606716f); + const __m256 K3 = _mm256_set1_ps(0.078024523f); + const __m256 log2_E = _mm256_set1_ps(1.44269504); + const __m256 max_in = _mm256_set1_ps(50.f); + const __m256 min_in = _mm256_set1_ps(-50.f); + const __m256i mask = _mm256_set1_epi32(0x7fffffff); + __m256 XF, Y; + __m256i I; + X = _mm256_mul_ps(X, log2_E); + X = _mm256_max_ps(min_in, _mm256_min_ps(max_in, X)); + XF = _mm256_floor_ps(X); + I = _mm256_cvtps_epi32(XF); + X = _mm256_sub_ps(X, XF); + Y = _mm256_fmadd_ps(_mm256_fmadd_ps(_mm256_fmadd_ps(K3, X, K2), X, K1), X, K0); + I = _mm256_slli_epi32(I, 23); + Y = _mm256_castsi256_ps(_mm256_and_si256(mask, _mm256_add_epi32(I, _mm256_castps_si256(Y)))); + return Y; +} +#else +#define _mm256_fmadd_ps(a,b,c) _mm256_add_ps(_mm256_mul_ps(a, b), c) +#define _mm_fmadd_ps(a,b,c) _mm_add_ps(_mm_mul_ps(a, b), c) +static __m128 exp4_approx(__m128 X) +{ + const __m128 K0 = _mm_set1_ps(0.99992522f); + const __m128 K1 = _mm_set1_ps(0.69583354f); + const __m128 K2 = _mm_set1_ps(0.22606716f); + const __m128 K3 = _mm_set1_ps(0.078024523f); + const __m128 log2_E = _mm_set1_ps(1.44269504); + const __m128 max_in = _mm_set1_ps(50.f); + const __m128 min_in = _mm_set1_ps(-50.f); + const __m128i mask = _mm_set1_epi32(0x7fffffff); + __m128 XF, Y; + __m128i I; + X = _mm_mul_ps(X, log2_E); + X = _mm_max_ps(min_in, _mm_min_ps(max_in, X)); + XF = _mm_floor_ps(X); + I = _mm_cvtps_epi32(XF); + X = _mm_sub_ps(X, XF); + Y = _mm_fmadd_ps(_mm_fmadd_ps(_mm_fmadd_ps(K3, X, K2), X, K1), X, K0); + I = _mm_slli_epi32(I, 23); + Y = _mm_castsi128_ps(_mm_and_si128(mask, _mm_add_epi32(I, _mm_castps_si128(Y)))); + return Y; +} +static __m256 exp8_approx(__m256 X) +{ + __m256 Y; + __m128 Xhi, Xlo, Yhi, Ylo; + Xhi = _mm256_extractf128_ps(X, 1); + Xlo = _mm256_extractf128_ps(X, 0); + Yhi = exp4_approx(Xhi); + Ylo = exp4_approx(Xlo); + Y = _mm256_insertf128_ps(_mm256_setzero_ps(), Yhi, 1); + Y = _mm256_insertf128_ps(Y, Ylo, 0); + return Y; +} +#endif + +static float celt_exp(float x) +{ + float out[8]; + __m256 X, Y; + X = _mm256_set1_ps(x); + Y = exp8_approx(X); + _mm256_storeu_ps(out, Y); + return out[0]; +} + +static void softmax(float *y, const float *x, int N) +{ + int i; + for (i=0;i +#ifndef LPCNET_TEST +static float celt_exp2(float x) +{ + int integer; + float frac; + union { + float f; + opus_uint32 i; + } res; + integer = floor(x); + if (integer < -50) + return 0; + frac = x-integer; + /* K0 = 1, K1 = log(2), K2 = 3-4*log(2), K3 = 3*log(2) - 2 */ + res.f = 0.99992522f + frac * (0.69583354f + + frac * (0.22606716f + 0.078024523f*frac)); + res.i = (res.i + (integer<<23)) & 0x7fffffff; + return res.f; +} +#define celt_exp_neon(x) celt_exp2((x)*1.44269504f) + +static float tansig_approx(float x) +{ + int i; + float y, dy; + float sign=1; + /* Tests are reversed to catch NaNs */ + if (!(x<8)) + return 1; + if (!(x>-8)) + return -1; +#ifndef FIXED_POINT + /* Another check in case of -ffast-math */ + if (celt_isnan(x)) + return 0; +#endif + if (x<0) + { + x=-x; + sign=-1; + } + i = (int)floor(.5f+25*x); + x -= .04f*i; + y = tansig_table[i]; + dy = 1-y*y; + y = y + x*dy*(1 - y*x); + return sign*y; +} + +static OPUS_INLINE float sigmoid_approx(float x) +{ + return .5f + .5f*tansig_approx(.5f*x); +} + +static void softmax(float *y, const float *x, int N) +{ + int i; + for (i=0;i