Skip to content

Commit

Permalink
Merge pull request #6329 from hrydgard/vfpu-sincos
Browse files Browse the repository at this point in the history
VFPU: Ensure that sin(4*x) returns 0.0 (and cos 1) for all x. Fixes #2921
  • Loading branch information
hrydgard committed Jun 15, 2014
2 parents 9503603 + e6f55bf commit a325049
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 30 deletions.
12 changes: 3 additions & 9 deletions Core/MIPS/ARM/ArmCompVFPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1832,24 +1832,18 @@ namespace MIPSComp
fpr.ReleaseSpillLocksAndDiscardTemps();
}

#ifndef M_PI_2
#define M_PI_2 1.57079632679489661923
#endif
// sincosf is unavailable in the Android NDK:
// https://code.google.com/p/android/issues/detail?id=38423
double SinCos(float angle) {
union { struct { float sin; float cos; }; double out; } sincos;
angle *= (float)M_PI_2;
sincos.sin = sinf(angle);
sincos.cos = cosf(angle);
vfpu_sincos(angle, sincos.sin, sincos.cos);
return sincos.out;
}

double SinCosNegSin(float angle) {
union { struct { float sin; float cos; }; double out; } sincos;
angle *= (float)M_PI_2;
sincos.sin = -sinf(angle);
sincos.cos = cosf(angle);
vfpu_sincos(angle, sincos.sin, sincos.cos);
sincos.sin = -sincos.sin;
return sincos.out;
}

Expand Down
3 changes: 3 additions & 0 deletions Core/MIPS/MIPS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ u8 fromvoffset[128];
#define M_LN10 2.30258509299404568402f
#undef M_PI
#define M_PI 3.14159265358979323846f

#ifndef M_PI_2
#define M_PI_2 1.57079632679489661923f
#endif
#define M_PI_4 0.785398163397448309616f
#define M_1_PI 0.318309886183790671538f
#define M_2_PI 0.636619772367581343076f
Expand Down
22 changes: 11 additions & 11 deletions Core/MIPS/MIPSIntVFPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@
#define M_LN10 2.30258509299404568402f
#undef M_PI
#define M_PI 3.14159265358979323846f
#ifndef M_PI_2
#define M_PI_2 1.57079632679489661923f
#endif
#define M_PI_4 0.785398163397448309616f
#define M_1_PI 0.318309886183790671538f
#define M_2_PI 0.636619772367581343076f
Expand Down Expand Up @@ -517,14 +519,15 @@ namespace MIPSInt
case 5: if (s[i] < -1.0f) d[i] = -1.0f; else {if(s[i] > 1.0f) d[i] = 1.0f; else d[i] = s[i];} break; // vsat1
case 16: d[i] = 1.0f / s[i]; break; //vrcp
case 17: d[i] = 1.0f / sqrtf(s[i]); break; //vrsq
case 18: d[i] = sinf((float)M_PI_2 * s[i]); break; //vsin
case 19: d[i] = cosf((float)M_PI_2 * s[i]); break; //vcos

case 18: { d[i] = vfpu_sin(s[i]); } break; //vsin
case 19: { d[i] = vfpu_cos(s[i]); } break; //vcos
case 20: d[i] = powf(2.0f, s[i]); break; //vexp2
case 21: d[i] = logf(s[i])/log(2.0f); break; //vlog2
case 22: d[i] = fabsf(sqrtf(s[i])); break; //vsqrt
case 23: d[i] = asinf(s[i]) / M_PI_2; break; //vasin
case 24: d[i] = -1.0f / s[i]; break; // vnrcp
case 26: d[i] = -sinf((float)M_PI_2 * s[i]); break; // vnsin
case 26: { d[i] = -vfpu_sin(s[i]); } break; // vnsin
case 28: d[i] = 1.0f / powf(2.0, s[i]); break; // vrexp2
default:
_dbg_assert_msg_(CPU,0,"Trying to interpret VV2Op instruction that can't be interpreted");
Expand Down Expand Up @@ -1285,21 +1288,18 @@ namespace MIPSInt
}

// Generates one line of a rotation matrix around one of the three axes
void Int_Vrot(MIPSOpcode op)
{
void Int_Vrot(MIPSOpcode op) {
int vd = _VD;
int vs = _VS;
int imm = (op >> 16) & 0x1f;
VectorSize sz = GetVecSize(op);
float angle = V(vs) * M_PI_2;
bool negSin = (imm & 0x10) ? true : false;
float sine = sinf(angle);
float cosine = cosf(angle);
float sine, cosine;
vfpu_sincos(V(vs), sine, cosine);
if (negSin)
sine = -sine;
float d[4] = {0};
if (((imm >> 2) & 3) == (imm & 3))
{
if (((imm >> 2) & 3) == (imm & 3)) {
for (int i = 0; i < 4; i++)
d[i] = sine;
}
Expand Down Expand Up @@ -1845,7 +1845,7 @@ namespace MIPSInt
ERROR_LOG_REPORT(CPU, "vsbn not implemented for size %d", GetNumVectorElements(sz));
}
for (int i = 0; i < GetNumVectorElements(sz); ++i) {
// Simply replace the expontent bits.
// Simply replace the exponent bits.
u32 prev = s.u[i] & 0x7F800000;
if (prev != 0 && prev != 0x7F800000) {
d.u[i] = (s.u[i] & ~0x7F800000) | (exp << 23);
Expand Down
28 changes: 26 additions & 2 deletions Core/MIPS/MIPSVFPUUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,41 @@

#pragma once

#include <cmath>

#include "Core/MIPS/MIPS.h"

#define _VD (op & 0x7F)
#define _VS ((op>>8) & 0x7F)
#define _VT ((op>>16) & 0x7F)

inline int Xpose(int v)
{
inline int Xpose(int v) {
return v^0x20;
}

#ifndef M_PI_2
#define M_PI_2 1.57079632679489661923
#endif

inline float vfpu_sin(float angle) {
angle -= floorf(angle * 0.25f) * 4.f;
angle *= (float)M_PI_2;
return sinf(angle);
}

inline float vfpu_cos(float angle) {
angle -= floorf(angle * 0.25f) * 4.f;
angle *= (float)M_PI_2;
return cosf(angle);
}

inline void vfpu_sincos(float angle, float &sine, float &cosine) {
angle -= floorf(angle * 0.25f) * 4.f;
angle *= (float)M_PI_2;
sine = sinf(angle);
cosine = cosf(angle);
}

#define VFPU_FLOAT16_EXP_MAX 0x1f
#define VFPU_SH_FLOAT16_SIGN 15
#define VFPU_MASK_FLOAT16_SIGN 0x1
Expand Down
9 changes: 3 additions & 6 deletions Core/MIPS/x86/CompVFPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2125,15 +2125,12 @@ typedef u32float SinCosArg;
#endif

void SinCos(SinCosArg angle) {
angle *= (float)1.57079632679489661923; // pi / 2
sincostemp[0] = sinf(angle);
sincostemp[1] = cosf(angle);
vfpu_sincos(angle, sincostemp[0], sincostemp[1]);
}

void SinCosNegSin(SinCosArg angle) {
angle *= (float)1.57079632679489661923; // pi / 2
sincostemp[0] = -sinf(angle);
sincostemp[1] = cosf(angle);
vfpu_sincos(angle, sincostemp[0], sincostemp[1]);
sincostemp[0] = -sincostemp[0];
}

// Very heavily used by FF:CC
Expand Down
36 changes: 34 additions & 2 deletions unittest/UnitTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@
#include "math/math_util.h"
#include "util/text/parsers.h"
#include "Core/Config.h"
#include "Core/MIPS/MIPSVFPUUtils.h"

#define EXPECT_TRUE(a) if (!(a)) { printf("%s:%i: Test Fail\n", __FUNCTION__, __LINE__); return false; }
#define EXPECT_FALSE(a) if ((a)) { printf("%s:%i: Test Fail\n", __FUNCTION__, __LINE__); return false; }
#define EXPECT_EQ_FLOAT(a, b) if ((a) != (b)) { printf("%s:" __LINE__ ": Test Fail\n%f\nvs\n%f\n", __FUNCTION__, a, b); return false; }
#define EXPECT_EQ_FLOAT(a, b) if ((a) != (b)) { printf("%s:%i: Test Fail\n%f\nvs\n%f\n", __FUNCTION__, __LINE__, a, b); return false; }
#define EXPECT_APPROX_EQ_FLOAT(a, b) if (fabsf((a)-(b))>0.00001f) { printf("%s:%i: Test Fail\n%f\nvs\n%f\n", __FUNCTION__, __LINE__, a, b); /*return false;*/ }
#define EXPECT_EQ_STR(a, b) if (a != b) { printf("%s: Test Fail\n%s\nvs\n%s\n", __FUNCTION__, a.c_str(), b.c_str()); return false; }

#define RET(a) if (!(a)) { return false; }
Expand Down Expand Up @@ -385,6 +387,35 @@ bool TestParsers() {
return true;
}

bool TestVFPUSinCos() {
float sine, cosine;
vfpu_sincos(0.0f, sine, cosine);
EXPECT_EQ_FLOAT(sine, 0.0f);
EXPECT_EQ_FLOAT(cosine, 1.0f);
vfpu_sincos(1.0f, sine, cosine);
EXPECT_APPROX_EQ_FLOAT(sine, 1.0f);
EXPECT_APPROX_EQ_FLOAT(cosine, 0.0f);
vfpu_sincos(2.0f, sine, cosine);
EXPECT_APPROX_EQ_FLOAT(sine, 0.0f);
EXPECT_APPROX_EQ_FLOAT(cosine, -1.0f);
vfpu_sincos(3.0f, sine, cosine);
EXPECT_APPROX_EQ_FLOAT(sine, -1.0f);
EXPECT_APPROX_EQ_FLOAT(cosine, 0.0f);
vfpu_sincos(4.0f, sine, cosine);
EXPECT_EQ_FLOAT(sine, 0.0f);
EXPECT_EQ_FLOAT(cosine, 1.0f);
vfpu_sincos(5.0f, sine, cosine);
EXPECT_APPROX_EQ_FLOAT(sine, 1.0f);
EXPECT_APPROX_EQ_FLOAT(cosine, 0.0f);

for (float angle = -10.0f; angle < 10.0f; angle++) {
vfpu_sincos(angle, sine, cosine);
EXPECT_APPROX_EQ_FLOAT(sine, sinf(angle * M_PI_2));
EXPECT_APPROX_EQ_FLOAT(cosine, cosf(angle * M_PI_2));
}
return true;
}

int main(int argc, const char *argv[]) {
cpu_info.bNEON = true;
cpu_info.bVFP = true;
Expand All @@ -393,7 +424,8 @@ int main(int argc, const char *argv[]) {
g_Config.bEnableLogging = true;
//TestAsin();
//TestSinCos();
TestArmEmitter();
//TestArmEmitter();
TestVFPUSinCos();
//TestMathUtil();
//TestParsers();
return 0;
Expand Down

0 comments on commit a325049

Please sign in to comment.