Merge pull request #2662 from Tilka/interpreter
Interpreter: turn SNaNs into QNaNs
This commit is contained in:
commit
b174f99b17
|
@ -209,23 +209,23 @@ double ApproximateReciprocal(double val)
|
|||
|
||||
// Special case 0
|
||||
if (mantissa == 0 && exponent == 0)
|
||||
return sign ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity();
|
||||
return std::copysign(std::numeric_limits<double>::infinity(), valf);
|
||||
|
||||
// Special case NaN-ish numbers
|
||||
if (exponent == (0x7FFLL << 52))
|
||||
{
|
||||
if (mantissa == 0)
|
||||
return sign ? -0.0 : 0.0;
|
||||
return std::copysign(0.0, valf);
|
||||
return 0.0 + valf;
|
||||
}
|
||||
|
||||
// Special case small inputs
|
||||
if (exponent < (895LL << 52))
|
||||
return sign ? -std::numeric_limits<float>::max() : std::numeric_limits<float>::max();
|
||||
return std::copysign(std::numeric_limits<float>::max(), valf);
|
||||
|
||||
// Special case large inputs
|
||||
if (exponent >= (1149LL << 52))
|
||||
return sign ? -0.0f : 0.0f;
|
||||
return std::copysign(0.0, valf);
|
||||
|
||||
exponent = (0x7FDLL << 52) - exponent;
|
||||
|
||||
|
|
|
@ -12,9 +12,6 @@
|
|||
#include "Core/PowerPC/Gekko.h"
|
||||
#include "Core/PowerPC/Interpreter/Interpreter.h"
|
||||
|
||||
#define MIN_SINGLE 0xc7efffffe0000000ull
|
||||
#define MAX_SINGLE 0x47efffffe0000000ull
|
||||
|
||||
const u64 PPC_NAN_U64 = 0x7ff8000000000000ull;
|
||||
const double PPC_NAN = *(double* const)&PPC_NAN_U64;
|
||||
|
||||
|
@ -79,6 +76,13 @@ inline double Force25Bit(double d)
|
|||
return x.d;
|
||||
}
|
||||
|
||||
inline double MakeQuiet(double d)
|
||||
{
|
||||
MathUtil::IntDouble x(d);
|
||||
x.i |= MathUtil::DOUBLE_QBIT;
|
||||
return x.d;
|
||||
}
|
||||
|
||||
// these functions allow globally modify operations behaviour
|
||||
// also, these may be used to set flags like FR, FI, OX, UX
|
||||
|
||||
|
@ -87,21 +91,43 @@ inline double NI_mul(double a, double b)
|
|||
double t = a * b;
|
||||
if (std::isnan(t))
|
||||
{
|
||||
if (std::isnan(a)) return a;
|
||||
if (std::isnan(b)) return b;
|
||||
if (std::isnan(a)) return MakeQuiet(a);
|
||||
if (std::isnan(b)) return MakeQuiet(b);
|
||||
SetFPException(FPSCR_VXIMZ);
|
||||
return PPC_NAN;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
inline double NI_div(double a, double b)
|
||||
{
|
||||
double t = a / b;
|
||||
if (std::isnan(t))
|
||||
{
|
||||
if (std::isnan(a)) return MakeQuiet(a);
|
||||
if (std::isnan(b)) return MakeQuiet(b);
|
||||
if (b == 0.0)
|
||||
{
|
||||
SetFPException(FPSCR_ZX);
|
||||
if (a == 0.0)
|
||||
SetFPException(FPSCR_VXZDZ);
|
||||
}
|
||||
else if (std::isinf(a) && std::isinf(b))
|
||||
{
|
||||
SetFPException(FPSCR_VXIDI);
|
||||
}
|
||||
return PPC_NAN;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
inline double NI_add(double a, double b)
|
||||
{
|
||||
double t = a + b;
|
||||
if (std::isnan(t))
|
||||
{
|
||||
if (std::isnan(a)) return a;
|
||||
if (std::isnan(b)) return b;
|
||||
if (std::isnan(a)) return MakeQuiet(a);
|
||||
if (std::isnan(b)) return MakeQuiet(b);
|
||||
SetFPException(FPSCR_VXISI);
|
||||
return PPC_NAN;
|
||||
}
|
||||
|
@ -113,8 +139,8 @@ inline double NI_sub(double a, double b)
|
|||
double t = a - b;
|
||||
if (std::isnan(t))
|
||||
{
|
||||
if (std::isnan(a)) return a;
|
||||
if (std::isnan(b)) return b;
|
||||
if (std::isnan(a)) return MakeQuiet(a);
|
||||
if (std::isnan(b)) return MakeQuiet(b);
|
||||
SetFPException(FPSCR_VXISI);
|
||||
return PPC_NAN;
|
||||
}
|
||||
|
@ -129,16 +155,16 @@ inline double NI_madd(double a, double c, double b, bool negate = false)
|
|||
double t = a * c;
|
||||
if (std::isnan(t))
|
||||
{
|
||||
if (std::isnan(a)) return a;
|
||||
if (std::isnan(b)) return b; // !
|
||||
if (std::isnan(c)) return c;
|
||||
if (std::isnan(a)) return MakeQuiet(a);
|
||||
if (std::isnan(b)) return MakeQuiet(b); // !
|
||||
if (std::isnan(c)) return MakeQuiet(c);
|
||||
SetFPException(FPSCR_VXIMZ);
|
||||
return PPC_NAN;
|
||||
}
|
||||
t += b;
|
||||
if (std::isnan(t))
|
||||
{
|
||||
if (std::isnan(b)) return b;
|
||||
if (std::isnan(b)) return MakeQuiet(b);
|
||||
SetFPException(FPSCR_VXISI);
|
||||
return PPC_NAN;
|
||||
}
|
||||
|
@ -150,9 +176,9 @@ inline double NI_msub(double a, double c, double b, bool negate = false)
|
|||
double t = a * c;
|
||||
if (std::isnan(t))
|
||||
{
|
||||
if (std::isnan(a)) return a;
|
||||
if (std::isnan(b)) return b; // !
|
||||
if (std::isnan(c)) return c;
|
||||
if (std::isnan(a)) return MakeQuiet(a);
|
||||
if (std::isnan(b)) return MakeQuiet(b); // !
|
||||
if (std::isnan(c)) return MakeQuiet(c);
|
||||
SetFPException(FPSCR_VXIMZ);
|
||||
return PPC_NAN;
|
||||
}
|
||||
|
@ -160,7 +186,7 @@ inline double NI_msub(double a, double c, double b, bool negate = false)
|
|||
t -= b;
|
||||
if (std::isnan(t))
|
||||
{
|
||||
if (std::isnan(b)) return b;
|
||||
if (std::isnan(b)) return MakeQuiet(b);
|
||||
SetFPException(FPSCR_VXISI);
|
||||
return PPC_NAN;
|
||||
}
|
||||
|
|
|
@ -351,38 +351,7 @@ void Interpreter::faddsx(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::fdivx(UGeckoInstruction _inst)
|
||||
{
|
||||
double a = rPS0(_inst.FA);
|
||||
double b = rPS0(_inst.FB);
|
||||
|
||||
if (a != a)
|
||||
{
|
||||
rPS0(_inst.FD) = a;
|
||||
}
|
||||
else if (b != b)
|
||||
{
|
||||
rPS0(_inst.FD) = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
rPS0(_inst.FD) = ForceDouble(a / b);
|
||||
if (b == 0.0)
|
||||
{
|
||||
if (a == 0.0)
|
||||
{
|
||||
SetFPException(FPSCR_VXZDZ);
|
||||
rPS0(_inst.FD) = PPC_NAN;
|
||||
}
|
||||
SetFPException(FPSCR_ZX);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsINF(a) && IsINF(b))
|
||||
{
|
||||
SetFPException(FPSCR_VXIDI);
|
||||
rPS0(_inst.FD) = PPC_NAN;
|
||||
}
|
||||
}
|
||||
}
|
||||
rPS0(_inst.FD) = ForceDouble(NI_div(rPS0(_inst.FA), rPS0(_inst.FB)));
|
||||
UpdateFPRF(rPS0(_inst.FD));
|
||||
|
||||
// FR,FI,OX,UX???
|
||||
|
@ -391,41 +360,7 @@ void Interpreter::fdivx(UGeckoInstruction _inst)
|
|||
}
|
||||
void Interpreter::fdivsx(UGeckoInstruction _inst)
|
||||
{
|
||||
double a = rPS0(_inst.FA);
|
||||
double b = rPS0(_inst.FB);
|
||||
double res;
|
||||
|
||||
if (a != a)
|
||||
{
|
||||
res = a;
|
||||
}
|
||||
else if (b != b)
|
||||
{
|
||||
res = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = ForceSingle(a / b);
|
||||
if (b == 0.0)
|
||||
{
|
||||
if (a == 0.0)
|
||||
{
|
||||
SetFPException(FPSCR_VXZDZ);
|
||||
res = PPC_NAN;
|
||||
}
|
||||
SetFPException(FPSCR_ZX);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsINF(a) && IsINF(b))
|
||||
{
|
||||
SetFPException(FPSCR_VXIDI);
|
||||
res = PPC_NAN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rPS0(_inst.FD) = rPS1(_inst.FD) = res;
|
||||
rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_div(rPS0(_inst.FA), rPS0(_inst.FB)));
|
||||
UpdateFPRF(rPS0(_inst.FD));
|
||||
|
||||
if (_inst.Rc)
|
||||
|
|
|
@ -59,10 +59,8 @@ void Interpreter::ps_abs(UGeckoInstruction _inst)
|
|||
// These are just moves, double is OK.
|
||||
void Interpreter::ps_merge00(UGeckoInstruction _inst)
|
||||
{
|
||||
double p0 = rPS0(_inst.FA);
|
||||
double p1 = rPS0(_inst.FB);
|
||||
rPS0(_inst.FD) = p0;
|
||||
rPS1(_inst.FD) = p1;
|
||||
rPS0(_inst.FD) = rPS0(_inst.FA);
|
||||
rPS1(_inst.FD) = rPS0(_inst.FB);
|
||||
|
||||
if (_inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
|
@ -70,10 +68,8 @@ void Interpreter::ps_merge00(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::ps_merge01(UGeckoInstruction _inst)
|
||||
{
|
||||
double p0 = rPS0(_inst.FA);
|
||||
double p1 = rPS1(_inst.FB);
|
||||
rPS0(_inst.FD) = p0;
|
||||
rPS1(_inst.FD) = p1;
|
||||
rPS0(_inst.FD) = rPS0(_inst.FA);
|
||||
rPS1(_inst.FD) = rPS1(_inst.FB);
|
||||
|
||||
if (_inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
|
@ -81,10 +77,8 @@ void Interpreter::ps_merge01(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::ps_merge10(UGeckoInstruction _inst)
|
||||
{
|
||||
double p0 = rPS1(_inst.FA);
|
||||
double p1 = rPS0(_inst.FB);
|
||||
rPS0(_inst.FD) = p0;
|
||||
rPS1(_inst.FD) = p1;
|
||||
rPS0(_inst.FD) = rPS1(_inst.FA);
|
||||
rPS1(_inst.FD) = rPS0(_inst.FB);
|
||||
|
||||
if (_inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
|
@ -92,10 +86,8 @@ void Interpreter::ps_merge10(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::ps_merge11(UGeckoInstruction _inst)
|
||||
{
|
||||
double p0 = rPS1(_inst.FA);
|
||||
double p1 = rPS1(_inst.FB);
|
||||
rPS0(_inst.FD) = p0;
|
||||
rPS1(_inst.FD) = p1;
|
||||
rPS0(_inst.FD) = rPS1(_inst.FA);
|
||||
rPS1(_inst.FD) = rPS1(_inst.FB);
|
||||
|
||||
if (_inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
|
@ -104,97 +96,8 @@ void Interpreter::ps_merge11(UGeckoInstruction _inst)
|
|||
// From here on, the real deal.
|
||||
void Interpreter::ps_div(UGeckoInstruction _inst)
|
||||
{
|
||||
u32 ex_mask = 0;
|
||||
|
||||
// PS0
|
||||
{
|
||||
double a = rPS0(_inst.FA);
|
||||
double b = rPS0(_inst.FB);
|
||||
double &res = rPS0(_inst.FD);
|
||||
|
||||
if (a != a)
|
||||
{
|
||||
res = a;
|
||||
}
|
||||
else if (b != b)
|
||||
{
|
||||
res = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (b == 0.0)
|
||||
{
|
||||
ex_mask |= FPSCR_ZX;
|
||||
if (rPS0(_inst.FA) == 0.0)
|
||||
{
|
||||
ex_mask |= FPSCR_VXZDZ;
|
||||
res = PPC_NAN;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = ForceSingle(a / b);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsINF(a) && IsINF(b))
|
||||
{
|
||||
ex_mask |= FPSCR_VXIDI;
|
||||
res = PPC_NAN;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = ForceSingle(a / b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PS1
|
||||
{
|
||||
double a = rPS1(_inst.FA);
|
||||
double b = rPS1(_inst.FB);
|
||||
double &res = rPS1(_inst.FD);
|
||||
|
||||
if (a != a)
|
||||
{
|
||||
res = a;
|
||||
}
|
||||
else if (b != b)
|
||||
{
|
||||
res = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (b == 0.0)
|
||||
{
|
||||
ex_mask |= FPSCR_ZX;
|
||||
if (rPS0(_inst.FA) == 0.0)
|
||||
{
|
||||
ex_mask |= FPSCR_VXZDZ;
|
||||
res = PPC_NAN;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = ForceSingle(a / b);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsINF(a) && IsINF(b))
|
||||
{
|
||||
ex_mask |= FPSCR_VXIDI;
|
||||
res = PPC_NAN;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = ForceSingle(a / b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetFPException(ex_mask);
|
||||
rPS0(_inst.FD) = ForceSingle(NI_div(rPS0(_inst.FA), rPS0(_inst.FB)));
|
||||
rPS1(_inst.FD) = ForceSingle(NI_div(rPS1(_inst.FA), rPS1(_inst.FB)));
|
||||
UpdateFPRF(rPS0(_inst.FD));
|
||||
|
||||
if (_inst.Rc)
|
||||
|
@ -325,10 +228,8 @@ void Interpreter::ps_nmadd(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::ps_sum0(UGeckoInstruction _inst)
|
||||
{
|
||||
double p0 = ForceSingle(NI_add(rPS0(_inst.FA), rPS1(_inst.FB)));
|
||||
double p1 = ForceSingle(rPS1(_inst.FC));
|
||||
rPS0(_inst.FD) = p0;
|
||||
rPS1(_inst.FD) = p1;
|
||||
rPS0(_inst.FD) = ForceSingle(NI_add(rPS0(_inst.FA), rPS1(_inst.FB)));
|
||||
rPS1(_inst.FD) = ForceSingle(rPS1(_inst.FC));
|
||||
UpdateFPRF(rPS0(_inst.FD));
|
||||
|
||||
if (_inst.Rc)
|
||||
|
@ -337,10 +238,8 @@ void Interpreter::ps_sum0(UGeckoInstruction _inst)
|
|||
|
||||
void Interpreter::ps_sum1(UGeckoInstruction _inst)
|
||||
{
|
||||
double p0 = ForceSingle(rPS0(_inst.FC));
|
||||
double p1 = ForceSingle(NI_add(rPS0(_inst.FA), rPS1(_inst.FB)));
|
||||
rPS0(_inst.FD) = p0;
|
||||
rPS1(_inst.FD) = p1;
|
||||
rPS0(_inst.FD) = ForceSingle(rPS0(_inst.FC));
|
||||
rPS1(_inst.FD) = ForceSingle(NI_add(rPS0(_inst.FA), rPS1(_inst.FB)));
|
||||
UpdateFPRF(rPS1(_inst.FD));
|
||||
|
||||
if (_inst.Rc)
|
||||
|
@ -350,10 +249,8 @@ void Interpreter::ps_sum1(UGeckoInstruction _inst)
|
|||
void Interpreter::ps_muls0(UGeckoInstruction _inst)
|
||||
{
|
||||
double c0 = Force25Bit(rPS0(_inst.FC));
|
||||
double p0 = ForceSingle(NI_mul(rPS0(_inst.FA), c0));
|
||||
double p1 = ForceSingle(NI_mul(rPS1(_inst.FA), c0));
|
||||
rPS0(_inst.FD) = p0;
|
||||
rPS1(_inst.FD) = p1;
|
||||
rPS0(_inst.FD) = ForceSingle(NI_mul(rPS0(_inst.FA), c0));
|
||||
rPS1(_inst.FD) = ForceSingle(NI_mul(rPS1(_inst.FA), c0));
|
||||
UpdateFPRF(rPS0(_inst.FD));
|
||||
|
||||
if (_inst.Rc)
|
||||
|
@ -363,10 +260,8 @@ void Interpreter::ps_muls0(UGeckoInstruction _inst)
|
|||
void Interpreter::ps_muls1(UGeckoInstruction _inst)
|
||||
{
|
||||
double c1 = Force25Bit(rPS1(_inst.FC));
|
||||
double p0 = ForceSingle(NI_mul(rPS0(_inst.FA), c1));
|
||||
double p1 = ForceSingle(NI_mul(rPS1(_inst.FA), c1));
|
||||
rPS0(_inst.FD) = p0;
|
||||
rPS1(_inst.FD) = p1;
|
||||
rPS0(_inst.FD) = ForceSingle(NI_mul(rPS0(_inst.FA), c1));
|
||||
rPS1(_inst.FD) = ForceSingle(NI_mul(rPS1(_inst.FA), c1));
|
||||
UpdateFPRF(rPS0(_inst.FD));
|
||||
|
||||
if (_inst.Rc)
|
||||
|
@ -376,10 +271,8 @@ void Interpreter::ps_muls1(UGeckoInstruction _inst)
|
|||
void Interpreter::ps_madds0(UGeckoInstruction _inst)
|
||||
{
|
||||
double c0 = Force25Bit(rPS0(_inst.FC));
|
||||
double p0 = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB)));
|
||||
double p1 = ForceSingle(NI_madd(rPS1(_inst.FA), c0, rPS1(_inst.FB)));
|
||||
rPS0(_inst.FD) = p0;
|
||||
rPS1(_inst.FD) = p1;
|
||||
rPS0(_inst.FD) = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB)));
|
||||
rPS1(_inst.FD) = ForceSingle(NI_madd(rPS1(_inst.FA), c0, rPS1(_inst.FB)));
|
||||
UpdateFPRF(rPS0(_inst.FD));
|
||||
|
||||
if (_inst.Rc)
|
||||
|
@ -389,10 +282,8 @@ void Interpreter::ps_madds0(UGeckoInstruction _inst)
|
|||
void Interpreter::ps_madds1(UGeckoInstruction _inst)
|
||||
{
|
||||
double c1 = Force25Bit(rPS1(_inst.FC));
|
||||
double p0 = ForceSingle(NI_madd(rPS0(_inst.FA), c1, rPS0(_inst.FB)));
|
||||
double p1 = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB)));
|
||||
rPS0(_inst.FD) = p0;
|
||||
rPS1(_inst.FD) = p1;
|
||||
rPS0(_inst.FD) = ForceSingle(NI_madd(rPS0(_inst.FA), c1, rPS0(_inst.FB)));
|
||||
rPS1(_inst.FD) = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB)));
|
||||
UpdateFPRF(rPS0(_inst.FD));
|
||||
|
||||
if (_inst.Rc)
|
||||
|
|
Loading…
Reference in New Issue