From 0d6a95093ffee3b7589a7d570f7762f8b4b26cb3 Mon Sep 17 00:00:00 2001 From: asmodai Date: Sat, 6 Feb 2016 03:41:32 +0300 Subject: [PATCH] Fixed mathlib unit tests Added popcnt support check Removed integer division optimization from asmlib.h Fixed typo in VectorCompare --- rehlds/engine/mathlib.cpp | 24 ++---- rehlds/public/asmlib.h | 101 ------------------------ rehlds/public/rehlds/sys_shared.cpp | 2 + rehlds/public/rehlds/sys_shared.h | 2 +- rehlds/unittests/mathlib_tests.cpp | 118 +++++++++++----------------- 5 files changed, 54 insertions(+), 193 deletions(-) diff --git a/rehlds/engine/mathlib.cpp b/rehlds/engine/mathlib.cpp index 10e09f3..9a754ae 100644 --- a/rehlds/engine/mathlib.cpp +++ b/rehlds/engine/mathlib.cpp @@ -340,10 +340,6 @@ void AngleVectors(const vec_t *angles, vec_t *forward, vec_t *right, vec_t *up) // parallel SSE version void AngleVectorsTranspose(const vec_t *angles, vec_t *forward, vec_t *right, vec_t *up) { -#ifndef SWDS - g_engdstAddrs.pfnAngleVectors(&angles, &forward, &right, &up); -#endif // SWDS - __m128 s, c; sincos_ps(_mm_mul_ps(_mm_loadu_ps(angles), _mm_load_ps(deg2rad)), &s, &c); @@ -425,10 +421,6 @@ void AngleVectorsTranspose(const vec_t *angles, vec_t *forward, vec_t *right, ve // parallel SSE version void AngleMatrix(const vec_t *angles, float(*matrix)[4]) { -#ifndef SWDS - g_engdstAddrs.pfnAngleVectors(&angles, &forward, &right, &up); -#endif // SWDS - __m128 s, c; sincos_ps(_mm_mul_ps(_mm_loadu_ps(angles), _mm_load_ps(deg2rad)), &s, &c); @@ -547,31 +539,27 @@ NOBODY void InterpolateAngles(float *start, float *end, float *output, float fra //} /* <47495> ../engine/mathlib.c:457 */ -//#ifndef REHLDS_FIXES - -//#else void VectorTransform(const vec_t *in1, float *in2, vec_t *out) { out[0] = _DotProduct(in1, in2 + 0) + in2[3]; out[1] = _DotProduct(in1, in2 + 4) + in2[7]; out[2] = _DotProduct(in1, in2 + 8) + in2[11]; } -//#endif /* <474dc> ../engine/mathlib.c:465 */ int VectorCompare(const vec_t *v1, const vec_t *v2) { -#ifdef REHLDS_FIXES - __m128 cmp = _mm_cmpneq_ss(_mm_loadu_ps(v1), _mm_loadu_ps(v2)); - return !(_mm_movemask_epi8(*(__m128i *)&cmp) & 0xFFFFFF); -#else +#ifdef REHLDS_OPT_PEDANTIC + __m128 cmp = _mm_cmpneq_ps(_mm_loadu_ps(v1), _mm_loadu_ps(v2)); + return !(_mm_movemask_epi8(*(__m128i *)&cmp) & 0xFFF); +#else // REHLDS_OPT_PEDANTIC for (int i = 0; i < 3; i++) { if (v1[i] != v2[i]) return 0; } return 1; -#endif +#endif // REHLDS_OPT_PEDANTIC } #ifdef REHLDS_FIXES @@ -775,7 +763,7 @@ NOBODY void R_ConcatRotations(float *in1, float *in2, float *out); /* <47a04> ../engine/mathlib.c:660 */ #ifdef REHLDS_FIXES -void NOINLINE R_ConcatTransforms(float in1[3][4], float in2[3][4], float out[3][4]) +void R_ConcatTransforms(float in1[3][4], float in2[3][4], float out[3][4]) { for (size_t i = 0; i < 3; i++) { diff --git a/rehlds/public/asmlib.h b/rehlds/public/asmlib.h index d95d13d..c1bc9af 100644 --- a/rehlds/public/asmlib.h +++ b/rehlds/public/asmlib.h @@ -120,105 +120,4 @@ static inline const char * A_strstr(const char * haystack, const char * needle) #endif // __cplusplus - -/*********************************************************************** -Function prototypes, integer division functions -***********************************************************************/ - -// Turn off name mangling -#ifdef __cplusplus -extern "C" { -#endif - -void setdivisori32(int buffer[2], int d); // Set divisor for repeated division -int dividefixedi32(const int buffer[2], int x); // Fast division with previously set divisor -void setdivisoru32(uint32_t buffer[2], uint32_t d); // Set divisor for repeated division -uint32_t dividefixedu32(const uint32_t buffer[2], uint32_t x); // Fast division with previously set divisor - -// Test if emmintrin.h is included and __m128i defined -#if defined(__GNUC__) && defined(_EMMINTRIN_H_INCLUDED) && !defined(__SSE2__) -#error Please compile with -sse2 or higher -#endif - -#if defined(_INCLUDED_EMM) || (defined(_EMMINTRIN_H_INCLUDED) && defined(__SSE2__)) -#define VECTORDIVISIONDEFINED - -// Integer vector division functions. These functions divide an integer vector by a scalar: - -// Set divisor for repeated integer vector division -void setdivisorV8i16(__m128i buf[2], int16_t d); // Set divisor for repeated division -void setdivisorV8u16(__m128i buf[2], uint16_t d); // Set divisor for repeated division -void setdivisorV4i32(__m128i buf[2], int32_t d); // Set divisor for repeated division -void setdivisorV4u32(__m128i buf[2], uint32_t d); // Set divisor for repeated division - -// Fast division of vector by previously set divisor -__m128i dividefixedV8i16(const __m128i buf[2], __m128i x); // Fast division with previously set divisor -__m128i dividefixedV8u16(const __m128i buf[2], __m128i x); // Fast division with previously set divisor -__m128i dividefixedV4i32(const __m128i buf[2], __m128i x); // Fast division with previously set divisor -__m128i dividefixedV4u32(const __m128i buf[2], __m128i x); // Fast division with previously set divisor - -#endif // defined(_INCLUDED_EMM) || (defined(_EMMINTRIN_H_INCLUDED) && defined(__SSE2__)) - -#ifdef __cplusplus -} // end of extern "C" -#endif // __cplusplus - -#ifdef __cplusplus - -// Define classes and operator '/' for fast division with fixed divisor -class div_i32; -class div_u32; -static inline int32_t operator / (int32_t x, div_i32 const &D); -static inline uint32_t operator / (uint32_t x, div_u32 const & D); - -class div_i32 { // Signed 32 bit integer division -public: - div_i32() { // Default constructor - buffer[0] = buffer[1] = 0; - } - div_i32(int d) { // Constructor with divisor - setdivisor(d); - } - void setdivisor(int d) { // Set divisor - setdivisori32(buffer, d); - } -protected: - int buffer[2]; // Internal memory - friend int32_t operator / (int32_t x, div_i32 const & D); -}; - -static inline int32_t operator / (int32_t x, div_i32 const &D){// Overloaded operator '/' - return dividefixedi32(D.buffer, x); -} - -static inline int32_t operator /= (int32_t &x, div_i32 const &D){// Overloaded operator '/=' - return x = x / D; -} - -class div_u32 { // Unsigned 32 bit integer division -public: - div_u32() { // Default constructor - buffer[0] = buffer[1] = 0; - } - div_u32(uint32_t d) { // Constructor with divisor - setdivisor(d); - } - void setdivisor(uint32_t d) { // Set divisor - setdivisoru32(buffer, d); - } -protected: - uint32_t buffer[2]; // Internal memory - friend uint32_t operator / (uint32_t x, div_u32 const & D); -}; - -static inline uint32_t operator / (uint32_t x, div_u32 const & D){ // Overloaded operator '/' - return dividefixedu32(D.buffer, x); -} - -static inline uint32_t operator /= (uint32_t &x, div_u32 const &D){// Overloaded operator '/=' - return x = x / D; -} - -#endif // __cplusplus - #endif // ASMLIB_H diff --git a/rehlds/public/rehlds/sys_shared.cpp b/rehlds/public/rehlds/sys_shared.cpp index e671f46..385b778 100644 --- a/rehlds/public/rehlds/sys_shared.cpp +++ b/rehlds/public/rehlds/sys_shared.cpp @@ -35,6 +35,7 @@ #define SSSE3_FLAG (1<<9) #define SSE4_1_FLAG (1<<19) #define SSE4_2_FLAG (1<<20) +#define POPCNT_FLAG (1<<23) #define AVX_FLAG (1<<28) #define AVX2_FLAG (1<<5) @@ -56,6 +57,7 @@ void Sys_CheckCpuInstructionsSupport(void) cpuinfo.ssse3 = (cpuid_data[2] & SSSE3_FLAG) ? 1 : 0; cpuinfo.sse4_1 = (cpuid_data[2] & SSE4_1_FLAG) ? 1 : 0; cpuinfo.sse4_2 = (cpuid_data[2] & SSE4_2_FLAG) ? 1 : 0; + cpuinfo.popcnt = (cpuid_data[2] & POPCNT_FLAG) ? 1 : 0; cpuinfo.avx = (cpuid_data[2] & AVX_FLAG) ? 1 : 0; #if defined ASMLIB_H diff --git a/rehlds/public/rehlds/sys_shared.h b/rehlds/public/rehlds/sys_shared.h index cc9ed72..768b51f 100644 --- a/rehlds/public/rehlds/sys_shared.h +++ b/rehlds/public/rehlds/sys_shared.h @@ -31,7 +31,7 @@ typedef struct cpuinfo_s { - uint8 sse3, ssse3, sse4_1, sse4_2, avx, avx2; + uint8 sse3, ssse3, sse4_1, sse4_2, avx, avx2, popcnt; } cpuinfo_t; extern cpuinfo_t cpuinfo; diff --git a/rehlds/unittests/mathlib_tests.cpp b/rehlds/unittests/mathlib_tests.cpp index ceeb62c..9b9475a 100644 --- a/rehlds/unittests/mathlib_tests.cpp +++ b/rehlds/unittests/mathlib_tests.cpp @@ -4,9 +4,6 @@ #include TEST(AngleVectorsTest, MathLib, 1000) { - Sys_CheckCpuInstructionsSupport(); - CHECK_WARNING_OUT("SSE4.1 Support", cpuinfo.sse4_1); - struct testdata_t { vec3_t angles; vec3_t forward, right, up; @@ -17,33 +14,26 @@ TEST(AngleVectorsTest, MathLib, 1000) { { { 106.0f, 142.0f, 62.0f }, { 0.21721f, -0.16970f, -0.96126f }, { 0.95785f, -0.15259f, 0.24337f }, { 0.18798f, 0.97361f, -0.12940f } } }; - for (int sse = 0; sse <= 1; sse++) { - vec3_t forward, right, up; + vec3_t forward, right, up; - for (int i = 0; i < ARRAYSIZE(testdata); i++) { - AngleVectors(testdata[i].angles, forward, right, up); + for (int i = 0; i < ARRAYSIZE(testdata); i++) { + AngleVectors(testdata[i].angles, forward, right, up); - DOUBLES_EQUAL("forward[0] mismatch", testdata[i].forward[0], forward[0], 0.00001); - DOUBLES_EQUAL("forward[1] mismatch", testdata[i].forward[1], forward[1], 0.00001); - DOUBLES_EQUAL("forward[2] mismatch", testdata[i].forward[2], forward[2], 0.00001); + DOUBLES_EQUAL("forward[0] mismatch", testdata[i].forward[0], forward[0], 0.00001); + DOUBLES_EQUAL("forward[1] mismatch", testdata[i].forward[1], forward[1], 0.00001); + DOUBLES_EQUAL("forward[2] mismatch", testdata[i].forward[2], forward[2], 0.00001); - DOUBLES_EQUAL("right[0] mismatch", testdata[i].right[0], right[0], 0.00001); - DOUBLES_EQUAL("right[1] mismatch", testdata[i].right[1], right[1], 0.00001); - DOUBLES_EQUAL("right[2] mismatch", testdata[i].right[2], right[2], 0.00001); + DOUBLES_EQUAL("right[0] mismatch", testdata[i].right[0], right[0], 0.00001); + DOUBLES_EQUAL("right[1] mismatch", testdata[i].right[1], right[1], 0.00001); + DOUBLES_EQUAL("right[2] mismatch", testdata[i].right[2], right[2], 0.00001); - DOUBLES_EQUAL("up[0] mismatch", testdata[i].up[0], up[0], 0.00001); - DOUBLES_EQUAL("up[1] mismatch", testdata[i].up[1], up[1], 0.00001); - DOUBLES_EQUAL("up[2] mismatch", testdata[i].up[2], up[2], 0.00001); - } - - cpuinfo.sse4_1 = 0; + DOUBLES_EQUAL("up[0] mismatch", testdata[i].up[0], up[0], 0.00001); + DOUBLES_EQUAL("up[1] mismatch", testdata[i].up[1], up[1], 0.00001); + DOUBLES_EQUAL("up[2] mismatch", testdata[i].up[2], up[2], 0.00001); } } TEST(AngleVectorsTransposeTest, MathLib, 1000) { - Sys_CheckCpuInstructionsSupport(); - CHECK_WARNING_OUT("SSE4.1 Support", cpuinfo.sse4_1); - struct testdata_t { vec3_t angles; vec3_t forward, right, up; @@ -54,33 +44,26 @@ TEST(AngleVectorsTransposeTest, MathLib, 1000) { { { 106.0f, 142.0f, 62.0f }, { 0.21721f, -0.95785f, 0.18798f }, { -0.16970f, 0.15259f, 0.97361f }, { -0.96126f, -0.24337f, -0.12940f } } }; - for (int sse = 0; sse <= 1; sse++) { - vec3_t forward, right, up; + vec3_t forward, right, up; - for (int i = 0; i < ARRAYSIZE(testdata); i++) { - AngleVectorsTranspose(testdata[i].angles, forward, right, up); + for (int i = 0; i < ARRAYSIZE(testdata); i++) { + AngleVectorsTranspose(testdata[i].angles, forward, right, up); - DOUBLES_EQUAL("forward[0] mismatch", testdata[i].forward[0], forward[0], 0.00001); - DOUBLES_EQUAL("forward[1] mismatch", testdata[i].forward[1], forward[1], 0.00001); - DOUBLES_EQUAL("forward[2] mismatch", testdata[i].forward[2], forward[2], 0.00001); + DOUBLES_EQUAL("forward[0] mismatch", testdata[i].forward[0], forward[0], 0.00001); + DOUBLES_EQUAL("forward[1] mismatch", testdata[i].forward[1], forward[1], 0.00001); + DOUBLES_EQUAL("forward[2] mismatch", testdata[i].forward[2], forward[2], 0.00001); - DOUBLES_EQUAL("right[0] mismatch", testdata[i].right[0], right[0], 0.00001); - DOUBLES_EQUAL("right[1] mismatch", testdata[i].right[1], right[1], 0.00001); - DOUBLES_EQUAL("right[2] mismatch", testdata[i].right[2], right[2], 0.00001); + DOUBLES_EQUAL("right[0] mismatch", testdata[i].right[0], right[0], 0.00001); + DOUBLES_EQUAL("right[1] mismatch", testdata[i].right[1], right[1], 0.00001); + DOUBLES_EQUAL("right[2] mismatch", testdata[i].right[2], right[2], 0.00001); - DOUBLES_EQUAL("up[0] mismatch", testdata[i].up[0], up[0], 0.00001); - DOUBLES_EQUAL("up[1] mismatch", testdata[i].up[1], up[1], 0.00001); - DOUBLES_EQUAL("up[2] mismatch", testdata[i].up[2], up[2], 0.00001); - } - - cpuinfo.sse4_1 = 0; + DOUBLES_EQUAL("up[0] mismatch", testdata[i].up[0], up[0], 0.00001); + DOUBLES_EQUAL("up[1] mismatch", testdata[i].up[1], up[1], 0.00001); + DOUBLES_EQUAL("up[2] mismatch", testdata[i].up[2], up[2], 0.00001); } } TEST(AngleMatrixTest, MathLib, 1000) { - Sys_CheckCpuInstructionsSupport(); - CHECK_WARNING_OUT("SSE4.1 Support", cpuinfo.sse4_1); - struct testdata_t { vec3_t angles; vec_t matrix0[4]; @@ -93,29 +76,25 @@ TEST(AngleMatrixTest, MathLib, 1000) { { { 106.0f, 142.0f, 62.0f }, { 0.21721f, -0.95785f, 0.18798f, 0.0f }, { -0.16970f, 0.15259f, 0.97361f, 0.0f }, { -0.96126f, -0.24337f, -0.12940f, 0.0f } } }; - for (int sse = 0; sse <= 1; sse++) { - float rotation_matrix[3][4]; + float rotation_matrix[3][4]; - for (int i = 0; i < ARRAYSIZE(testdata); i++) { - AngleMatrix(testdata[i].angles, rotation_matrix); + for (int i = 0; i < ARRAYSIZE(testdata); i++) { + AngleMatrix(testdata[i].angles, rotation_matrix); - DOUBLES_EQUAL("rotationmatrix[0][0] mismatch", testdata[i].matrix0[0], rotation_matrix[0][0], 0.00001); - DOUBLES_EQUAL("rotationmatrix[0][1] mismatch", testdata[i].matrix0[1], rotation_matrix[0][1], 0.00001); - DOUBLES_EQUAL("rotationmatrix[0][2] mismatch", testdata[i].matrix0[2], rotation_matrix[0][2], 0.00001); - DOUBLES_EQUAL("rotationmatrix[0][3] mismatch", testdata[i].matrix0[3], rotation_matrix[0][3], 0.00001); + DOUBLES_EQUAL("rotationmatrix[0][0] mismatch", testdata[i].matrix0[0], rotation_matrix[0][0], 0.00001); + DOUBLES_EQUAL("rotationmatrix[0][1] mismatch", testdata[i].matrix0[1], rotation_matrix[0][1], 0.00001); + DOUBLES_EQUAL("rotationmatrix[0][2] mismatch", testdata[i].matrix0[2], rotation_matrix[0][2], 0.00001); + DOUBLES_EQUAL("rotationmatrix[0][3] mismatch", testdata[i].matrix0[3], rotation_matrix[0][3], 0.00001); - DOUBLES_EQUAL("rotationmatrix[1][0] mismatch", testdata[i].matrix1[0], rotation_matrix[1][0], 0.00001); - DOUBLES_EQUAL("rotationmatrix[1][1] mismatch", testdata[i].matrix1[1], rotation_matrix[1][1], 0.00001); - DOUBLES_EQUAL("rotationmatrix[1][2] mismatch", testdata[i].matrix1[2], rotation_matrix[1][2], 0.00001); - DOUBLES_EQUAL("rotationmatrix[1][3] mismatch", testdata[i].matrix1[3], rotation_matrix[1][3], 0.00001); + DOUBLES_EQUAL("rotationmatrix[1][0] mismatch", testdata[i].matrix1[0], rotation_matrix[1][0], 0.00001); + DOUBLES_EQUAL("rotationmatrix[1][1] mismatch", testdata[i].matrix1[1], rotation_matrix[1][1], 0.00001); + DOUBLES_EQUAL("rotationmatrix[1][2] mismatch", testdata[i].matrix1[2], rotation_matrix[1][2], 0.00001); + DOUBLES_EQUAL("rotationmatrix[1][3] mismatch", testdata[i].matrix1[3], rotation_matrix[1][3], 0.00001); - DOUBLES_EQUAL("rotationmatrix[2][0] mismatch", testdata[i].matrix2[0], rotation_matrix[2][0], 0.00001); - DOUBLES_EQUAL("rotationmatrix[2][1] mismatch", testdata[i].matrix2[1], rotation_matrix[2][1], 0.00001); - DOUBLES_EQUAL("rotationmatrix[2][2] mismatch", testdata[i].matrix2[2], rotation_matrix[2][2], 0.00001); - DOUBLES_EQUAL("rotationmatrix[2][3] mismatch", testdata[i].matrix2[3], rotation_matrix[2][3], 0.00001); - } - - cpuinfo.sse4_1 = 0; + DOUBLES_EQUAL("rotationmatrix[2][0] mismatch", testdata[i].matrix2[0], rotation_matrix[2][0], 0.00001); + DOUBLES_EQUAL("rotationmatrix[2][1] mismatch", testdata[i].matrix2[1], rotation_matrix[2][1], 0.00001); + DOUBLES_EQUAL("rotationmatrix[2][2] mismatch", testdata[i].matrix2[2], rotation_matrix[2][2], 0.00001); + DOUBLES_EQUAL("rotationmatrix[2][3] mismatch", testdata[i].matrix2[3], rotation_matrix[2][3], 0.00001); } } @@ -146,9 +125,6 @@ TEST(DotProductTest, MathLib, 1000) { } TEST(CrossProductTest, MathLib, 1000) { - Sys_CheckCpuInstructionsSupport(); - CHECK_WARNING_OUT("SSE4.1 Support", cpuinfo.sse4_1); - struct testdata_t { vec3_t v1; vec3_t v2; @@ -160,18 +136,14 @@ TEST(CrossProductTest, MathLib, 1000) { { { -16.1f, -0.09f, 1.2f }, { 8.2f, 1.2f, -6.66f }, { -0.84060f, -97.38600f, -18.58200f } }, }; - for (int sse = 0; sse <= 1; sse++) { - vec3_t res; + vec3_t res; - for (int i = 0; i < ARRAYSIZE(testdata); i++) { - CrossProduct(testdata[i].v1, testdata[i].v2, res); + for (int i = 0; i < ARRAYSIZE(testdata); i++) { + CrossProduct(testdata[i].v1, testdata[i].v2, res); - DOUBLES_EQUAL("CrossProduct[0] mismatch", testdata[i].res[0], res[0], 0.00001); - DOUBLES_EQUAL("CrossProduct[1] mismatch", testdata[i].res[1], res[1], 0.00001); - DOUBLES_EQUAL("CrossProduct[2] mismatch", testdata[i].res[2], res[2], 0.00001); - } - - cpuinfo.sse4_1 = 0; + DOUBLES_EQUAL("CrossProduct[0] mismatch", testdata[i].res[0], res[0], 0.00001); + DOUBLES_EQUAL("CrossProduct[1] mismatch", testdata[i].res[1], res[1], 0.00001); + DOUBLES_EQUAL("CrossProduct[2] mismatch", testdata[i].res[2], res[2], 0.00001); } }