Permalink
Browse files

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.
  • Loading branch information...
lioncash committed Jun 3, 2018
1 parent c22205c commit 9068109b3ed00f6960d1554b1532f763ca84014a
@@ -103,18 +103,16 @@ inline double NI_mul(double a, double b)
if (std::isnan(t))
{
if (Common::IsSNAN(a) || Common::IsSNAN(b))
{
SetFPException(FPSCR_VXSNAN);
FPSCR.ClearFIFR();
}
FPSCR.ClearFIFR();
if (std::isnan(a))
return MakeQuiet(a);
if (std::isnan(b))
return MakeQuiet(b);
SetFPException(FPSCR_VXIMZ);
FPSCR.ClearFIFR();
return PPC_NAN;
}
return t;
@@ -127,10 +125,9 @@ inline double NI_div(double a, double b)
if (std::isnan(t))
{
if (Common::IsSNAN(a) || Common::IsSNAN(b))
{
SetFPException(FPSCR_VXSNAN);
FPSCR.ClearFIFR();
}
FPSCR.ClearFIFR();
if (std::isnan(a))
return MakeQuiet(a);
@@ -142,18 +139,15 @@ inline double NI_div(double a, double b)
if (a == 0.0)
{
SetFPException(FPSCR_VXZDZ);
FPSCR.ClearFIFR();
}
else
{
SetFPException(FPSCR_ZX);
FPSCR.ClearFIFR();
}
}
else if (std::isinf(a) && std::isinf(b))
{
SetFPException(FPSCR_VXIDI);
FPSCR.ClearFIFR();
}
return PPC_NAN;
@@ -169,21 +163,22 @@ inline double NI_add(double a, double b)
if (std::isnan(t))
{
if (Common::IsSNAN(a) || Common::IsSNAN(b))
{
SetFPException(FPSCR_VXSNAN);
FPSCR.ClearFIFR();
}
FPSCR.ClearFIFR();
if (std::isnan(a))
return MakeQuiet(a);
if (std::isnan(b))
return MakeQuiet(b);
SetFPException(FPSCR_VXISI);
FPSCR.ClearFIFR();
return PPC_NAN;
}
if (std::isinf(a) || std::isinf(b))
FPSCR.ClearFIFR();
return t;
}
@@ -194,21 +189,22 @@ inline double NI_sub(double a, double b)
if (std::isnan(t))
{
if (Common::IsSNAN(a) || Common::IsSNAN(b))
{
SetFPException(FPSCR_VXSNAN);
FPSCR.ClearFIFR();
}
FPSCR.ClearFIFR();
if (std::isnan(a))
return MakeQuiet(a);
if (std::isnan(b))
return MakeQuiet(b);
SetFPException(FPSCR_VXISI);
FPSCR.ClearFIFR();
return PPC_NAN;
}
if (std::isinf(a) || std::isinf(b))
FPSCR.ClearFIFR();
return t;
}
@@ -222,10 +218,9 @@ inline double NI_madd(double a, double c, double b)
if (std::isnan(t))
{
if (Common::IsSNAN(a) || Common::IsSNAN(b) || Common::IsSNAN(c))
{
SetFPException(FPSCR_VXSNAN);
FPSCR.ClearFIFR();
}
FPSCR.ClearFIFR();
if (std::isnan(a))
return MakeQuiet(a);
@@ -235,7 +230,6 @@ inline double NI_madd(double a, double c, double b)
return MakeQuiet(c);
SetFPException(FPSCR_VXIMZ);
FPSCR.ClearFIFR();
return PPC_NAN;
}
@@ -244,19 +238,20 @@ inline double NI_madd(double a, double c, double b)
if (std::isnan(t))
{
if (Common::IsSNAN(b))
{
SetFPException(FPSCR_VXSNAN);
FPSCR.ClearFIFR();
}
FPSCR.ClearFIFR();
if (std::isnan(b))
return MakeQuiet(b);
SetFPException(FPSCR_VXISI);
FPSCR.ClearFIFR();
return PPC_NAN;
}
if (std::isinf(a) || std::isinf(b) || std::isinf(c))
FPSCR.ClearFIFR();
return t;
}
@@ -267,10 +262,9 @@ inline double NI_msub(double a, double c, double b)
if (std::isnan(t))
{
if (Common::IsSNAN(a) || Common::IsSNAN(b) || Common::IsSNAN(c))
{
SetFPException(FPSCR_VXSNAN);
FPSCR.ClearFIFR();
}
FPSCR.ClearFIFR();
if (std::isnan(a))
return MakeQuiet(a);
@@ -280,7 +274,6 @@ inline double NI_msub(double a, double c, double b)
return MakeQuiet(c);
SetFPException(FPSCR_VXIMZ);
FPSCR.ClearFIFR();
return PPC_NAN;
}
@@ -289,19 +282,20 @@ inline double NI_msub(double a, double c, double b)
if (std::isnan(t))
{
if (Common::IsSNAN(b))
{
SetFPException(FPSCR_VXSNAN);
FPSCR.ClearFIFR();
}
FPSCR.ClearFIFR();
if (std::isnan(b))
return MakeQuiet(b);
SetFPException(FPSCR_VXISI);
FPSCR.ClearFIFR();
return PPC_NAN;
}
if (std::isinf(a) || std::isinf(b) || std::isinf(c))
FPSCR.ClearFIFR();
return t;
}
@@ -409,6 +409,9 @@ void Interpreter::fresx(UGeckoInstruction inst)
}
else
{
if (std::isnan(b) || std::isinf(b))
FPSCR.ClearFIFR();
compute_result(b);
}
@@ -452,6 +455,9 @@ void Interpreter::frsqrtex(UGeckoInstruction inst)
}
else
{
if (std::isnan(b) || std::isinf(b))
FPSCR.ClearFIFR();
compute_result(b);
}
@@ -124,11 +124,11 @@ void Interpreter::ps_res(UGeckoInstruction inst)
FPSCR.ClearFIFR();
}
if (std::isnan(a) || std::isinf(a) || std::isnan(b) || std::isinf(b))
FPSCR.ClearFIFR();
if (Common::IsSNAN(a) || Common::IsSNAN(b))
{
SetFPException(FPSCR_VXSNAN);
FPSCR.ClearFIFR();
}
rPS0(inst.FD) = Common::ApproximateReciprocal(a);
rPS1(inst.FD) = Common::ApproximateReciprocal(b);
@@ -155,11 +155,11 @@ void Interpreter::ps_rsqrte(UGeckoInstruction inst)
FPSCR.ClearFIFR();
}
if (std::isnan(ps0) || std::isinf(ps0) || std::isnan(ps1) || std::isinf(ps1))
FPSCR.ClearFIFR();
if (Common::IsSNAN(ps0) || Common::IsSNAN(ps1))
{
SetFPException(FPSCR_VXSNAN);
FPSCR.ClearFIFR();
}
rPS0(inst.FD) = ForceSingle(Common::ApproximateReciprocalSquareRoot(ps0));
rPS1(inst.FD) = ForceSingle(Common::ApproximateReciprocalSquareRoot(ps1));

0 comments on commit 9068109

Please sign in to comment.