1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-23 03:02:53 +01:00

Implement host FP exception checking for PPU floating-point instructions.

This commit is contained in:
Andrew Church 2015-01-18 21:14:31 +09:00
parent 04902965fe
commit 3a87a40593

View File

@ -81,6 +81,7 @@ static void SetHostRoundingMode(u32 rn)
} }
} }
namespace ppu_recompiler_llvm { namespace ppu_recompiler_llvm {
class Compiler; class Compiler;
} }
@ -100,6 +101,13 @@ public:
} }
private: private:
void CheckHostFPExceptions()
{
CPU.SetFPSCR_FI(fetestexcept(FE_INEXACT) != 0);
if (fetestexcept(FE_UNDERFLOW)) CPU.SetFPSCRException(FPSCR_UX);
if (fetestexcept(FE_OVERFLOW)) CPU.SetFPSCRException(FPSCR_OX);
}
void Exit() {} void Exit() {}
void SysCall() void SysCall()
@ -3727,7 +3735,9 @@ private:
} }
else else
{ {
feclearexcept(FE_ALL_EXCEPT);
CPU.FPR[frd] = static_cast<float>(1.0 / b); CPU.FPR[frd] = static_cast<float>(1.0 / b);
CheckHostFPExceptions();
} }
CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); CPU.FPSCR.FPRF = CPU.FPR[frd].GetType();
if(rc) CPU.UpdateCR1(); if(rc) CPU.UpdateCR1();
@ -3849,6 +3859,7 @@ private:
{ {
if (((u64&)b0 & DOUBLE_EXP) < 0x3800000000000000ULL) (u64&)b0 &= DOUBLE_SIGN; if (((u64&)b0 & DOUBLE_EXP) < 0x3800000000000000ULL) (u64&)b0 &= DOUBLE_SIGN;
} }
feclearexcept(FE_ALL_EXCEPT);
const double r = static_cast<float>(b0); const double r = static_cast<float>(b0);
if (FPRdouble::IsNaN(r)) if (FPRdouble::IsNaN(r))
{ {
@ -3858,7 +3869,7 @@ private:
else else
{ {
CPU.FPSCR.FR = fabs(r) > fabs(b); CPU.FPSCR.FR = fabs(r) > fabs(b);
CPU.SetFPSCR_FI(b != r); CheckHostFPExceptions();
} }
u32 type = PPCdouble(r).GetType(); u32 type = PPCdouble(r).GetType();
if (type == FPR_PN && r < ldexp(1.0, -126)) type = FPR_PD; if (type == FPR_PN && r < ldexp(1.0, -126)) type = FPR_PD;
@ -3997,9 +4008,11 @@ private:
return; return;
} }
} }
feclearexcept(FE_ALL_EXCEPT);
const double res = a / b; const double res = a / b;
if(single) CPU.FPR[frd] = (float)res; if(single) CPU.FPR[frd] = (float)res;
else CPU.FPR[frd] = res; else CPU.FPR[frd] = res;
CheckHostFPExceptions();
} }
CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); CPU.FPSCR.FPRF = CPU.FPR[frd].GetType();
@ -4044,9 +4057,11 @@ private:
} }
else else
{ {
feclearexcept(FE_ALL_EXCEPT);
const double res = a - b; const double res = a - b;
if(single) CPU.FPR[frd] = (float)res; if(single) CPU.FPR[frd] = (float)res;
else CPU.FPR[frd] = res; else CPU.FPR[frd] = res;
CheckHostFPExceptions();
} }
CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); CPU.FPSCR.FPRF = CPU.FPR[frd].GetType();
if(rc) CPU.UpdateCR1(); if(rc) CPU.UpdateCR1();
@ -4090,9 +4105,11 @@ private:
} }
else else
{ {
feclearexcept(FE_ALL_EXCEPT);
const double res = a + b; const double res = a + b;
if(single) CPU.FPR[frd] = (float)res; if(single) CPU.FPR[frd] = (float)res;
else CPU.FPR[frd] = res; else CPU.FPR[frd] = res;
CheckHostFPExceptions();
} }
CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); CPU.FPSCR.FPRF = CPU.FPR[frd].GetType();
if(rc) CPU.UpdateCR1(); if(rc) CPU.UpdateCR1();
@ -4131,9 +4148,11 @@ private:
} }
else else
{ {
feclearexcept(FE_ALL_EXCEPT);
const double res = sqrt(b); const double res = sqrt(b);
if(single) CPU.FPR[frd] = (float)res; if(single) CPU.FPR[frd] = (float)res;
else CPU.FPR[frd] = res; else CPU.FPR[frd] = res;
CheckHostFPExceptions();
} }
CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); CPU.FPSCR.FPRF = CPU.FPR[frd].GetType();
if(rc) CPU.UpdateCR1(); if(rc) CPU.UpdateCR1();
@ -4182,9 +4201,11 @@ private:
} }
else else
{ {
feclearexcept(FE_ALL_EXCEPT);
const double res = a * c; const double res = a * c;
if(single) CPU.FPR[frd] = (float)res; if(single) CPU.FPR[frd] = (float)res;
else CPU.FPR[frd] = res; else CPU.FPR[frd] = res;
CheckHostFPExceptions();
} }
CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); CPU.FPSCR.FPRF = CPU.FPR[frd].GetType();
if(rc) CPU.UpdateCR1(); if(rc) CPU.UpdateCR1();
@ -4234,7 +4255,9 @@ private:
} }
else else
{ {
feclearexcept(FE_ALL_EXCEPT);
CPU.FPR[frd] = 1.0 / sqrt(b); CPU.FPR[frd] = 1.0 / sqrt(b);
CheckHostFPExceptions();
} }
CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); CPU.FPSCR.FPRF = CPU.FPR[frd].GetType();
if(rc) CPU.UpdateCR1(); if(rc) CPU.UpdateCR1();
@ -4299,8 +4322,10 @@ private:
} }
else else
{ {
feclearexcept(FE_ALL_EXCEPT);
if(single) CPU.FPR[frd] = (float)(neg ? -res : res); if(single) CPU.FPR[frd] = (float)(neg ? -res : res);
else CPU.FPR[frd] = (neg ? -res : res); else CPU.FPR[frd] = (neg ? -res : res);
CheckHostFPExceptions();
} }
} }
CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); CPU.FPSCR.FPRF = CPU.FPR[frd].GetType();