Interpreter: Unset FPSCR.FI and FPSCR.FR for QNaN and infinity input operands
This hardware behavior makes sense, as the FI bit is used to signify an inexact result. An inexact result is a form of value that results during the rounding phase of denormalization. If any bits of the significand are lost during said rounding, then the result is considered to be inexact. However NaN and infinity are not classed as subnormals and therefore don't undergo the denormalization step, making loss of precision not possible (in NaN's case, numerically rounding something that is literally Not a Number doesn't even make sense). FR is set to indicate whether or not the last arithmetic or rounding and conversion instruction that rounded the intermediate result incremented the fractional portion of the result. Given neither input types would be affected by this, this should also be unset. This corrects more of the exceptional case handling for these values to match hardware.
This commit is contained in:
parent
c22205cd7e
commit
9068109b3e
|
@ -103,10 +103,9 @@ inline double NI_mul(double a, double b)
|
||||||
if (std::isnan(t))
|
if (std::isnan(t))
|
||||||
{
|
{
|
||||||
if (Common::IsSNAN(a) || Common::IsSNAN(b))
|
if (Common::IsSNAN(a) || Common::IsSNAN(b))
|
||||||
{
|
|
||||||
SetFPException(FPSCR_VXSNAN);
|
SetFPException(FPSCR_VXSNAN);
|
||||||
FPSCR.ClearFIFR();
|
|
||||||
}
|
FPSCR.ClearFIFR();
|
||||||
|
|
||||||
if (std::isnan(a))
|
if (std::isnan(a))
|
||||||
return MakeQuiet(a);
|
return MakeQuiet(a);
|
||||||
|
@ -114,7 +113,6 @@ inline double NI_mul(double a, double b)
|
||||||
return MakeQuiet(b);
|
return MakeQuiet(b);
|
||||||
|
|
||||||
SetFPException(FPSCR_VXIMZ);
|
SetFPException(FPSCR_VXIMZ);
|
||||||
FPSCR.ClearFIFR();
|
|
||||||
return PPC_NAN;
|
return PPC_NAN;
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
|
@ -127,10 +125,9 @@ inline double NI_div(double a, double b)
|
||||||
if (std::isnan(t))
|
if (std::isnan(t))
|
||||||
{
|
{
|
||||||
if (Common::IsSNAN(a) || Common::IsSNAN(b))
|
if (Common::IsSNAN(a) || Common::IsSNAN(b))
|
||||||
{
|
|
||||||
SetFPException(FPSCR_VXSNAN);
|
SetFPException(FPSCR_VXSNAN);
|
||||||
FPSCR.ClearFIFR();
|
|
||||||
}
|
FPSCR.ClearFIFR();
|
||||||
|
|
||||||
if (std::isnan(a))
|
if (std::isnan(a))
|
||||||
return MakeQuiet(a);
|
return MakeQuiet(a);
|
||||||
|
@ -142,18 +139,15 @@ inline double NI_div(double a, double b)
|
||||||
if (a == 0.0)
|
if (a == 0.0)
|
||||||
{
|
{
|
||||||
SetFPException(FPSCR_VXZDZ);
|
SetFPException(FPSCR_VXZDZ);
|
||||||
FPSCR.ClearFIFR();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SetFPException(FPSCR_ZX);
|
SetFPException(FPSCR_ZX);
|
||||||
FPSCR.ClearFIFR();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (std::isinf(a) && std::isinf(b))
|
else if (std::isinf(a) && std::isinf(b))
|
||||||
{
|
{
|
||||||
SetFPException(FPSCR_VXIDI);
|
SetFPException(FPSCR_VXIDI);
|
||||||
FPSCR.ClearFIFR();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return PPC_NAN;
|
return PPC_NAN;
|
||||||
|
@ -169,10 +163,9 @@ inline double NI_add(double a, double b)
|
||||||
if (std::isnan(t))
|
if (std::isnan(t))
|
||||||
{
|
{
|
||||||
if (Common::IsSNAN(a) || Common::IsSNAN(b))
|
if (Common::IsSNAN(a) || Common::IsSNAN(b))
|
||||||
{
|
|
||||||
SetFPException(FPSCR_VXSNAN);
|
SetFPException(FPSCR_VXSNAN);
|
||||||
FPSCR.ClearFIFR();
|
|
||||||
}
|
FPSCR.ClearFIFR();
|
||||||
|
|
||||||
if (std::isnan(a))
|
if (std::isnan(a))
|
||||||
return MakeQuiet(a);
|
return MakeQuiet(a);
|
||||||
|
@ -180,10 +173,12 @@ inline double NI_add(double a, double b)
|
||||||
return MakeQuiet(b);
|
return MakeQuiet(b);
|
||||||
|
|
||||||
SetFPException(FPSCR_VXISI);
|
SetFPException(FPSCR_VXISI);
|
||||||
FPSCR.ClearFIFR();
|
|
||||||
return PPC_NAN;
|
return PPC_NAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (std::isinf(a) || std::isinf(b))
|
||||||
|
FPSCR.ClearFIFR();
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,10 +189,9 @@ inline double NI_sub(double a, double b)
|
||||||
if (std::isnan(t))
|
if (std::isnan(t))
|
||||||
{
|
{
|
||||||
if (Common::IsSNAN(a) || Common::IsSNAN(b))
|
if (Common::IsSNAN(a) || Common::IsSNAN(b))
|
||||||
{
|
|
||||||
SetFPException(FPSCR_VXSNAN);
|
SetFPException(FPSCR_VXSNAN);
|
||||||
FPSCR.ClearFIFR();
|
|
||||||
}
|
FPSCR.ClearFIFR();
|
||||||
|
|
||||||
if (std::isnan(a))
|
if (std::isnan(a))
|
||||||
return MakeQuiet(a);
|
return MakeQuiet(a);
|
||||||
|
@ -205,10 +199,12 @@ inline double NI_sub(double a, double b)
|
||||||
return MakeQuiet(b);
|
return MakeQuiet(b);
|
||||||
|
|
||||||
SetFPException(FPSCR_VXISI);
|
SetFPException(FPSCR_VXISI);
|
||||||
FPSCR.ClearFIFR();
|
|
||||||
return PPC_NAN;
|
return PPC_NAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (std::isinf(a) || std::isinf(b))
|
||||||
|
FPSCR.ClearFIFR();
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,10 +218,9 @@ inline double NI_madd(double a, double c, double b)
|
||||||
if (std::isnan(t))
|
if (std::isnan(t))
|
||||||
{
|
{
|
||||||
if (Common::IsSNAN(a) || Common::IsSNAN(b) || Common::IsSNAN(c))
|
if (Common::IsSNAN(a) || Common::IsSNAN(b) || Common::IsSNAN(c))
|
||||||
{
|
|
||||||
SetFPException(FPSCR_VXSNAN);
|
SetFPException(FPSCR_VXSNAN);
|
||||||
FPSCR.ClearFIFR();
|
|
||||||
}
|
FPSCR.ClearFIFR();
|
||||||
|
|
||||||
if (std::isnan(a))
|
if (std::isnan(a))
|
||||||
return MakeQuiet(a);
|
return MakeQuiet(a);
|
||||||
|
@ -235,7 +230,6 @@ inline double NI_madd(double a, double c, double b)
|
||||||
return MakeQuiet(c);
|
return MakeQuiet(c);
|
||||||
|
|
||||||
SetFPException(FPSCR_VXIMZ);
|
SetFPException(FPSCR_VXIMZ);
|
||||||
FPSCR.ClearFIFR();
|
|
||||||
return PPC_NAN;
|
return PPC_NAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,19 +238,20 @@ inline double NI_madd(double a, double c, double b)
|
||||||
if (std::isnan(t))
|
if (std::isnan(t))
|
||||||
{
|
{
|
||||||
if (Common::IsSNAN(b))
|
if (Common::IsSNAN(b))
|
||||||
{
|
|
||||||
SetFPException(FPSCR_VXSNAN);
|
SetFPException(FPSCR_VXSNAN);
|
||||||
FPSCR.ClearFIFR();
|
|
||||||
}
|
FPSCR.ClearFIFR();
|
||||||
|
|
||||||
if (std::isnan(b))
|
if (std::isnan(b))
|
||||||
return MakeQuiet(b);
|
return MakeQuiet(b);
|
||||||
|
|
||||||
SetFPException(FPSCR_VXISI);
|
SetFPException(FPSCR_VXISI);
|
||||||
FPSCR.ClearFIFR();
|
|
||||||
return PPC_NAN;
|
return PPC_NAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (std::isinf(a) || std::isinf(b) || std::isinf(c))
|
||||||
|
FPSCR.ClearFIFR();
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,10 +262,9 @@ inline double NI_msub(double a, double c, double b)
|
||||||
if (std::isnan(t))
|
if (std::isnan(t))
|
||||||
{
|
{
|
||||||
if (Common::IsSNAN(a) || Common::IsSNAN(b) || Common::IsSNAN(c))
|
if (Common::IsSNAN(a) || Common::IsSNAN(b) || Common::IsSNAN(c))
|
||||||
{
|
|
||||||
SetFPException(FPSCR_VXSNAN);
|
SetFPException(FPSCR_VXSNAN);
|
||||||
FPSCR.ClearFIFR();
|
|
||||||
}
|
FPSCR.ClearFIFR();
|
||||||
|
|
||||||
if (std::isnan(a))
|
if (std::isnan(a))
|
||||||
return MakeQuiet(a);
|
return MakeQuiet(a);
|
||||||
|
@ -280,7 +274,6 @@ inline double NI_msub(double a, double c, double b)
|
||||||
return MakeQuiet(c);
|
return MakeQuiet(c);
|
||||||
|
|
||||||
SetFPException(FPSCR_VXIMZ);
|
SetFPException(FPSCR_VXIMZ);
|
||||||
FPSCR.ClearFIFR();
|
|
||||||
return PPC_NAN;
|
return PPC_NAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,19 +282,20 @@ inline double NI_msub(double a, double c, double b)
|
||||||
if (std::isnan(t))
|
if (std::isnan(t))
|
||||||
{
|
{
|
||||||
if (Common::IsSNAN(b))
|
if (Common::IsSNAN(b))
|
||||||
{
|
|
||||||
SetFPException(FPSCR_VXSNAN);
|
SetFPException(FPSCR_VXSNAN);
|
||||||
FPSCR.ClearFIFR();
|
|
||||||
}
|
FPSCR.ClearFIFR();
|
||||||
|
|
||||||
if (std::isnan(b))
|
if (std::isnan(b))
|
||||||
return MakeQuiet(b);
|
return MakeQuiet(b);
|
||||||
|
|
||||||
SetFPException(FPSCR_VXISI);
|
SetFPException(FPSCR_VXISI);
|
||||||
FPSCR.ClearFIFR();
|
|
||||||
return PPC_NAN;
|
return PPC_NAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (std::isinf(a) || std::isinf(b) || std::isinf(c))
|
||||||
|
FPSCR.ClearFIFR();
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -409,6 +409,9 @@ void Interpreter::fresx(UGeckoInstruction inst)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (std::isnan(b) || std::isinf(b))
|
||||||
|
FPSCR.ClearFIFR();
|
||||||
|
|
||||||
compute_result(b);
|
compute_result(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,6 +455,9 @@ void Interpreter::frsqrtex(UGeckoInstruction inst)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (std::isnan(b) || std::isinf(b))
|
||||||
|
FPSCR.ClearFIFR();
|
||||||
|
|
||||||
compute_result(b);
|
compute_result(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,11 +124,11 @@ void Interpreter::ps_res(UGeckoInstruction inst)
|
||||||
FPSCR.ClearFIFR();
|
FPSCR.ClearFIFR();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Common::IsSNAN(a) || Common::IsSNAN(b))
|
if (std::isnan(a) || std::isinf(a) || std::isnan(b) || std::isinf(b))
|
||||||
{
|
|
||||||
SetFPException(FPSCR_VXSNAN);
|
|
||||||
FPSCR.ClearFIFR();
|
FPSCR.ClearFIFR();
|
||||||
}
|
|
||||||
|
if (Common::IsSNAN(a) || Common::IsSNAN(b))
|
||||||
|
SetFPException(FPSCR_VXSNAN);
|
||||||
|
|
||||||
rPS0(inst.FD) = Common::ApproximateReciprocal(a);
|
rPS0(inst.FD) = Common::ApproximateReciprocal(a);
|
||||||
rPS1(inst.FD) = Common::ApproximateReciprocal(b);
|
rPS1(inst.FD) = Common::ApproximateReciprocal(b);
|
||||||
|
@ -155,11 +155,11 @@ void Interpreter::ps_rsqrte(UGeckoInstruction inst)
|
||||||
FPSCR.ClearFIFR();
|
FPSCR.ClearFIFR();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Common::IsSNAN(ps0) || Common::IsSNAN(ps1))
|
if (std::isnan(ps0) || std::isinf(ps0) || std::isnan(ps1) || std::isinf(ps1))
|
||||||
{
|
|
||||||
SetFPException(FPSCR_VXSNAN);
|
|
||||||
FPSCR.ClearFIFR();
|
FPSCR.ClearFIFR();
|
||||||
}
|
|
||||||
|
if (Common::IsSNAN(ps0) || Common::IsSNAN(ps1))
|
||||||
|
SetFPException(FPSCR_VXSNAN);
|
||||||
|
|
||||||
rPS0(inst.FD) = ForceSingle(Common::ApproximateReciprocalSquareRoot(ps0));
|
rPS0(inst.FD) = ForceSingle(Common::ApproximateReciprocalSquareRoot(ps0));
|
||||||
rPS1(inst.FD) = ForceSingle(Common::ApproximateReciprocalSquareRoot(ps1));
|
rPS1(inst.FD) = ForceSingle(Common::ApproximateReciprocalSquareRoot(ps1));
|
||||||
|
|
Loading…
Reference in New Issue