Interpreter_FPUtils: Unset FPSCR.FI and FPSCR.FR if an invalid operation occurs in NI_* functions

If an invalid operation occurs, FI and FR bits are defined to be cleared
to zero for arithmetic operations.
This commit is contained in:
Lioncash 2018-06-02 20:13:30 -04:00
parent 0f7370a22c
commit 468efb7243
1 changed files with 50 additions and 0 deletions

View File

@ -103,7 +103,11 @@ 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.FI = 0;
FPSCR.FR = 0;
}
if (std::isnan(a)) if (std::isnan(a))
return MakeQuiet(a); return MakeQuiet(a);
@ -111,6 +115,8 @@ inline double NI_mul(double a, double b)
return MakeQuiet(b); return MakeQuiet(b);
SetFPException(FPSCR_VXIMZ); SetFPException(FPSCR_VXIMZ);
FPSCR.FI = 0;
FPSCR.FR = 0;
return PPC_NAN; return PPC_NAN;
} }
return t; return t;
@ -123,7 +129,11 @@ 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.FI = 0;
FPSCR.FR = 0;
}
if (std::isnan(a)) if (std::isnan(a))
return MakeQuiet(a); return MakeQuiet(a);
@ -135,6 +145,8 @@ inline double NI_div(double a, double b)
if (a == 0.0) if (a == 0.0)
{ {
SetFPException(FPSCR_VXZDZ); SetFPException(FPSCR_VXZDZ);
FPSCR.FI = 0;
FPSCR.FR = 0;
} }
else else
{ {
@ -146,6 +158,8 @@ inline double NI_div(double a, double b)
else if (std::isinf(a) && std::isinf(b)) else if (std::isinf(a) && std::isinf(b))
{ {
SetFPException(FPSCR_VXIDI); SetFPException(FPSCR_VXIDI);
FPSCR.FI = 0;
FPSCR.FR = 0;
} }
return PPC_NAN; return PPC_NAN;
@ -161,7 +175,11 @@ 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.FI = 0;
FPSCR.FR = 0;
}
if (std::isnan(a)) if (std::isnan(a))
return MakeQuiet(a); return MakeQuiet(a);
@ -169,6 +187,8 @@ inline double NI_add(double a, double b)
return MakeQuiet(b); return MakeQuiet(b);
SetFPException(FPSCR_VXISI); SetFPException(FPSCR_VXISI);
FPSCR.FI = 0;
FPSCR.FR = 0;
return PPC_NAN; return PPC_NAN;
} }
@ -182,7 +202,11 @@ 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.FI = 0;
FPSCR.FR = 0;
}
if (std::isnan(a)) if (std::isnan(a))
return MakeQuiet(a); return MakeQuiet(a);
@ -190,6 +214,8 @@ inline double NI_sub(double a, double b)
return MakeQuiet(b); return MakeQuiet(b);
SetFPException(FPSCR_VXISI); SetFPException(FPSCR_VXISI);
FPSCR.FI = 0;
FPSCR.FR = 0;
return PPC_NAN; return PPC_NAN;
} }
@ -206,7 +232,11 @@ 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.FI = 0;
FPSCR.FR = 0;
}
if (std::isnan(a)) if (std::isnan(a))
return MakeQuiet(a); return MakeQuiet(a);
@ -216,6 +246,8 @@ inline double NI_madd(double a, double c, double b)
return MakeQuiet(c); return MakeQuiet(c);
SetFPException(FPSCR_VXIMZ); SetFPException(FPSCR_VXIMZ);
FPSCR.FI = 0;
FPSCR.FR = 0;
return PPC_NAN; return PPC_NAN;
} }
@ -224,12 +256,18 @@ 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.FI = 0;
FPSCR.FR = 0;
}
if (std::isnan(b)) if (std::isnan(b))
return MakeQuiet(b); return MakeQuiet(b);
SetFPException(FPSCR_VXISI); SetFPException(FPSCR_VXISI);
FPSCR.FI = 0;
FPSCR.FR = 0;
return PPC_NAN; return PPC_NAN;
} }
@ -243,7 +281,11 @@ 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.FI = 0;
FPSCR.FR = 0;
}
if (std::isnan(a)) if (std::isnan(a))
return MakeQuiet(a); return MakeQuiet(a);
@ -253,6 +295,8 @@ inline double NI_msub(double a, double c, double b)
return MakeQuiet(c); return MakeQuiet(c);
SetFPException(FPSCR_VXIMZ); SetFPException(FPSCR_VXIMZ);
FPSCR.FI = 0;
FPSCR.FR = 0;
return PPC_NAN; return PPC_NAN;
} }
@ -261,12 +305,18 @@ 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.FI = 0;
FPSCR.FR = 0;
}
if (std::isnan(b)) if (std::isnan(b))
return MakeQuiet(b); return MakeQuiet(b);
SetFPException(FPSCR_VXISI); SetFPException(FPSCR_VXISI);
FPSCR.FI = 0;
FPSCR.FR = 0;
return PPC_NAN; return PPC_NAN;
} }