Interpreter_FPUtils: Handle the FPSCR.ZE and FPSCR.VE flags with arithmetic instructions

According to PEM 3.3.6.1, if a division by zero occurs and FPSCR.ZE is
set, then the result of the instruction operation is unchanged (see
table 3-13). Similarly, if an invalid operation occurs and FPSCR.VE is
set, then the destination should also remain unchanged (see table 3-12).
Hardware also matches this behavior.

We were handling this for other relevant instructions, but we weren't
doing so for the arithmetic instructions. This corrects that.

This also alters our NI_* functions to return an FPResult type, which
allows us to see which kind of exception in particular is set in
exceptional cases. This is necessary for cases like the fdiv
instructions, which requires handling both ZE and VE being potentially
set.
This commit is contained in:
Lioncash 2018-06-19 15:17:29 -04:00
parent 18c3e0302f
commit 72e21bc679
3 changed files with 334 additions and 165 deletions

View File

@ -97,206 +97,280 @@ inline double MakeQuiet(double d)
// these functions allow globally modify operations behaviour
// also, these may be used to set flags like FR, FI, OX, UX
inline double NI_mul(double a, double b)
struct FPResult
{
const double t = a * b;
if (std::isnan(t))
bool HasNoInvalidExceptions() const { return (exception & FPSCR_VX_ANY) == 0; }
void SetException(FPSCRExceptionFlag flag)
{
exception = flag;
SetFPException(flag);
}
double value = 0.0;
FPSCRExceptionFlag exception{};
};
inline FPResult NI_mul(double a, double b)
{
FPResult result{a * b};
if (std::isnan(result.value))
{
if (Common::IsSNAN(a) || Common::IsSNAN(b))
SetFPException(FPSCR_VXSNAN);
{
result.SetException(FPSCR_VXSNAN);
}
FPSCR.ClearFIFR();
if (std::isnan(a))
return MakeQuiet(a);
{
result.value = MakeQuiet(a);
return result;
}
if (std::isnan(b))
return MakeQuiet(b);
{
result.value = MakeQuiet(b);
return result;
}
SetFPException(FPSCR_VXIMZ);
return PPC_NAN;
result.value = PPC_NAN;
result.SetException(FPSCR_VXIMZ);
return result;
}
return t;
return result;
}
inline double NI_div(double a, double b)
inline FPResult NI_div(double a, double b)
{
const double t = a / b;
FPResult result{a / b};
if (std::isnan(t))
if (std::isnan(result.value))
{
if (Common::IsSNAN(a) || Common::IsSNAN(b))
SetFPException(FPSCR_VXSNAN);
result.SetException(FPSCR_VXSNAN);
FPSCR.ClearFIFR();
if (std::isnan(a))
return MakeQuiet(a);
{
result.value = MakeQuiet(a);
return result;
}
if (std::isnan(b))
return MakeQuiet(b);
{
result.value = MakeQuiet(b);
return result;
}
if (b == 0.0)
{
if (a == 0.0)
{
SetFPException(FPSCR_VXZDZ);
result.SetException(FPSCR_VXZDZ);
}
else
{
SetFPException(FPSCR_ZX);
result.SetException(FPSCR_ZX);
}
}
else if (std::isinf(a) && std::isinf(b))
{
SetFPException(FPSCR_VXIDI);
result.SetException(FPSCR_VXIDI);
}
return PPC_NAN;
result.value = PPC_NAN;
return result;
}
return t;
return result;
}
inline double NI_add(double a, double b)
inline FPResult NI_add(double a, double b)
{
const double t = a + b;
FPResult result{a + b};
if (std::isnan(t))
if (std::isnan(result.value))
{
if (Common::IsSNAN(a) || Common::IsSNAN(b))
SetFPException(FPSCR_VXSNAN);
result.SetException(FPSCR_VXSNAN);
FPSCR.ClearFIFR();
if (std::isnan(a))
return MakeQuiet(a);
{
result.value = MakeQuiet(a);
return result;
}
if (std::isnan(b))
return MakeQuiet(b);
{
result.value = MakeQuiet(b);
return result;
}
SetFPException(FPSCR_VXISI);
return PPC_NAN;
result.SetException(FPSCR_VXISI);
result.value = PPC_NAN;
return result;
}
if (std::isinf(a) || std::isinf(b))
FPSCR.ClearFIFR();
return t;
return result;
}
inline double NI_sub(double a, double b)
inline FPResult NI_sub(double a, double b)
{
const double t = a - b;
FPResult result{a - b};
if (std::isnan(t))
if (std::isnan(result.value))
{
if (Common::IsSNAN(a) || Common::IsSNAN(b))
SetFPException(FPSCR_VXSNAN);
result.SetException(FPSCR_VXSNAN);
FPSCR.ClearFIFR();
if (std::isnan(a))
return MakeQuiet(a);
{
result.value = MakeQuiet(a);
return result;
}
if (std::isnan(b))
return MakeQuiet(b);
{
result.value = MakeQuiet(b);
return result;
}
SetFPException(FPSCR_VXISI);
return PPC_NAN;
result.SetException(FPSCR_VXISI);
result.value = PPC_NAN;
return result;
}
if (std::isinf(a) || std::isinf(b))
FPSCR.ClearFIFR();
return t;
return result;
}
// FMA instructions on PowerPC are weird:
// They calculate (a * c) + b, but the order in which
// inputs are checked for NaN is still a, b, c.
inline double NI_madd(double a, double c, double b)
inline FPResult NI_madd(double a, double c, double b)
{
double t = a * c;
FPResult result{a * c};
if (std::isnan(t))
if (std::isnan(result.value))
{
if (Common::IsSNAN(a) || Common::IsSNAN(b) || Common::IsSNAN(c))
SetFPException(FPSCR_VXSNAN);
result.SetException(FPSCR_VXSNAN);
FPSCR.ClearFIFR();
if (std::isnan(a))
return MakeQuiet(a);
{
result.value = MakeQuiet(a);
return result;
}
if (std::isnan(b))
return MakeQuiet(b); // !
{
result.value = MakeQuiet(b); // !
return result;
}
if (std::isnan(c))
return MakeQuiet(c);
{
result.value = MakeQuiet(c);
return result;
}
SetFPException(FPSCR_VXIMZ);
return PPC_NAN;
result.SetException(FPSCR_VXIMZ);
result.value = PPC_NAN;
return result;
}
t += b;
result.value += b;
if (std::isnan(t))
if (std::isnan(result.value))
{
if (Common::IsSNAN(b))
SetFPException(FPSCR_VXSNAN);
result.SetException(FPSCR_VXSNAN);
FPSCR.ClearFIFR();
if (std::isnan(b))
return MakeQuiet(b);
{
result.value = MakeQuiet(b);
return result;
}
SetFPException(FPSCR_VXISI);
return PPC_NAN;
result.SetException(FPSCR_VXISI);
result.value = PPC_NAN;
return result;
}
if (std::isinf(a) || std::isinf(b) || std::isinf(c))
FPSCR.ClearFIFR();
return t;
return result;
}
inline double NI_msub(double a, double c, double b)
inline FPResult NI_msub(double a, double c, double b)
{
double t = a * c;
FPResult result{a * c};
if (std::isnan(t))
if (std::isnan(result.value))
{
if (Common::IsSNAN(a) || Common::IsSNAN(b) || Common::IsSNAN(c))
SetFPException(FPSCR_VXSNAN);
result.SetException(FPSCR_VXSNAN);
FPSCR.ClearFIFR();
if (std::isnan(a))
return MakeQuiet(a);
{
result.value = MakeQuiet(a);
return result;
}
if (std::isnan(b))
return MakeQuiet(b); // !
{
result.value = MakeQuiet(b); // !
return result;
}
if (std::isnan(c))
return MakeQuiet(c);
{
result.value = MakeQuiet(c);
return result;
}
SetFPException(FPSCR_VXIMZ);
return PPC_NAN;
result.SetException(FPSCR_VXIMZ);
result.value = PPC_NAN;
return result;
}
t -= b;
result.value -= b;
if (std::isnan(t))
if (std::isnan(result.value))
{
if (Common::IsSNAN(b))
SetFPException(FPSCR_VXSNAN);
result.SetException(FPSCR_VXSNAN);
FPSCR.ClearFIFR();
if (std::isnan(b))
return MakeQuiet(b);
{
result.value = MakeQuiet(b);
return result;
}
SetFPException(FPSCR_VXISI);
return PPC_NAN;
result.SetException(FPSCR_VXISI);
result.value = PPC_NAN;
return result;
}
if (std::isinf(a) || std::isinf(b) || std::isinf(c))
FPSCR.ClearFIFR();
return t;
return result;
}
// used by stfsXX instructions and ps_rsqrte

View File

@ -300,23 +300,35 @@ void Interpreter::frspx(UGeckoInstruction inst) // round to single
void Interpreter::fmulx(UGeckoInstruction inst)
{
rPS0(inst.FD) = ForceDouble(NI_mul(rPS0(inst.FA), rPS0(inst.FC)));
FPSCR.FI = 0; // are these flags important?
FPSCR.FR = 0;
PowerPC::UpdateFPRF(rPS0(inst.FD));
const FPResult product = NI_mul(rPS0(inst.FA), rPS0(inst.FC));
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
{
const double result = ForceDouble(product.value);
rPS0(inst.FD) = result;
FPSCR.FI = 0; // are these flags important?
FPSCR.FR = 0;
PowerPC::UpdateFPRF(result);
}
if (inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::fmulsx(UGeckoInstruction inst)
{
double c_value = Force25Bit(rPS0(inst.FC));
double d_value = NI_mul(rPS0(inst.FA), c_value);
rPS0(inst.FD) = rPS1(inst.FD) = ForceSingle(d_value);
// FPSCR.FI = d_value != rPS0(_inst.FD);
FPSCR.FI = 0;
FPSCR.FR = 0;
PowerPC::UpdateFPRF(rPS0(inst.FD));
const double c_value = Force25Bit(rPS0(inst.FC));
const FPResult d_value = NI_mul(rPS0(inst.FA), c_value);
if (FPSCR.VE == 0 || d_value.HasNoInvalidExceptions())
{
const double result = ForceSingle(d_value.value);
rPS0(inst.FD) = rPS1(inst.FD) = result;
FPSCR.FI = 0;
FPSCR.FR = 0;
PowerPC::UpdateFPRF(result);
}
if (inst.Rc)
Helper_UpdateCR1();
@ -324,9 +336,14 @@ void Interpreter::fmulsx(UGeckoInstruction inst)
void Interpreter::fmaddx(UGeckoInstruction inst)
{
double result = ForceDouble(NI_madd(rPS0(inst.FA), rPS0(inst.FC), rPS0(inst.FB)));
rPS0(inst.FD) = result;
PowerPC::UpdateFPRF(result);
const FPResult product = NI_madd(rPS0(inst.FA), rPS0(inst.FC), rPS0(inst.FB));
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
{
const double result = ForceDouble(product.value);
rPS0(inst.FD) = result;
PowerPC::UpdateFPRF(result);
}
if (inst.Rc)
Helper_UpdateCR1();
@ -334,12 +351,18 @@ void Interpreter::fmaddx(UGeckoInstruction inst)
void Interpreter::fmaddsx(UGeckoInstruction inst)
{
double c_value = Force25Bit(rPS0(inst.FC));
double d_value = NI_madd(rPS0(inst.FA), c_value, rPS0(inst.FB));
rPS0(inst.FD) = rPS1(inst.FD) = ForceSingle(d_value);
FPSCR.FI = d_value != rPS0(inst.FD);
FPSCR.FR = 0;
PowerPC::UpdateFPRF(rPS0(inst.FD));
const double c_value = Force25Bit(rPS0(inst.FC));
const FPResult d_value = NI_madd(rPS0(inst.FA), c_value, rPS0(inst.FB));
if (FPSCR.VE == 0 || d_value.HasNoInvalidExceptions())
{
const double result = ForceSingle(d_value.value);
rPS0(inst.FD) = rPS1(inst.FD) = result;
FPSCR.FI = d_value.value != result;
FPSCR.FR = 0;
PowerPC::UpdateFPRF(result);
}
if (inst.Rc)
Helper_UpdateCR1();
@ -347,16 +370,28 @@ void Interpreter::fmaddsx(UGeckoInstruction inst)
void Interpreter::faddx(UGeckoInstruction inst)
{
rPS0(inst.FD) = ForceDouble(NI_add(rPS0(inst.FA), rPS0(inst.FB)));
PowerPC::UpdateFPRF(rPS0(inst.FD));
const FPResult sum = NI_add(rPS0(inst.FA), rPS0(inst.FB));
if (FPSCR.VE == 0 || sum.HasNoInvalidExceptions())
{
const double result = ForceDouble(sum.value);
rPS0(inst.FD) = result;
PowerPC::UpdateFPRF(result);
}
if (inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::faddsx(UGeckoInstruction inst)
{
rPS0(inst.FD) = rPS1(inst.FD) = ForceSingle(NI_add(rPS0(inst.FA), rPS0(inst.FB)));
PowerPC::UpdateFPRF(rPS0(inst.FD));
const FPResult sum = NI_add(rPS0(inst.FA), rPS0(inst.FB));
if (FPSCR.VE == 0 || sum.HasNoInvalidExceptions())
{
const double result = ForceSingle(sum.value);
rPS0(inst.FD) = rPS1(inst.FD) = result;
PowerPC::UpdateFPRF(result);
}
if (inst.Rc)
Helper_UpdateCR1();
@ -364,8 +399,16 @@ void Interpreter::faddsx(UGeckoInstruction inst)
void Interpreter::fdivx(UGeckoInstruction inst)
{
rPS0(inst.FD) = ForceDouble(NI_div(rPS0(inst.FA), rPS0(inst.FB)));
PowerPC::UpdateFPRF(rPS0(inst.FD));
const FPResult quotient = NI_div(rPS0(inst.FA), rPS0(inst.FB));
const bool not_divide_by_zero = FPSCR.ZE == 0 || quotient.exception != FPSCR_ZX;
const bool not_invalid = FPSCR.VE == 0 || quotient.HasNoInvalidExceptions();
if (not_divide_by_zero && not_invalid)
{
const double result = ForceDouble(quotient.value);
rPS0(inst.FD) = result;
PowerPC::UpdateFPRF(result);
}
// FR,FI,OX,UX???
if (inst.Rc)
@ -373,8 +416,16 @@ void Interpreter::fdivx(UGeckoInstruction inst)
}
void Interpreter::fdivsx(UGeckoInstruction inst)
{
rPS0(inst.FD) = rPS1(inst.FD) = ForceSingle(NI_div(rPS0(inst.FA), rPS0(inst.FB)));
PowerPC::UpdateFPRF(rPS0(inst.FD));
const FPResult quotient = NI_div(rPS0(inst.FA), rPS0(inst.FB));
const bool not_divide_by_zero = FPSCR.ZE == 0 || quotient.exception != FPSCR_ZX;
const bool not_invalid = FPSCR.VE == 0 || quotient.HasNoInvalidExceptions();
if (not_divide_by_zero && not_invalid)
{
const double result = ForceSingle(quotient.value);
rPS0(inst.FD) = rPS1(inst.FD) = result;
PowerPC::UpdateFPRF(result);
}
if (inst.Rc)
Helper_UpdateCR1();
@ -465,20 +516,32 @@ void Interpreter::frsqrtex(UGeckoInstruction inst)
Helper_UpdateCR1();
}
void Interpreter::fmsubx(UGeckoInstruction _inst)
void Interpreter::fmsubx(UGeckoInstruction inst)
{
rPS0(_inst.FD) = ForceDouble(NI_msub(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB)));
PowerPC::UpdateFPRF(rPS0(_inst.FD));
const FPResult product = NI_msub(rPS0(inst.FA), rPS0(inst.FC), rPS0(inst.FB));
if (_inst.Rc)
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
{
const double result = ForceDouble(product.value);
rPS0(inst.FD) = result;
PowerPC::UpdateFPRF(result);
}
if (inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::fmsubsx(UGeckoInstruction inst)
{
double c_value = Force25Bit(rPS0(inst.FC));
rPS0(inst.FD) = rPS1(inst.FD) = ForceSingle(NI_msub(rPS0(inst.FA), c_value, rPS0(inst.FB)));
PowerPC::UpdateFPRF(rPS0(inst.FD));
const double c_value = Force25Bit(rPS0(inst.FC));
const FPResult product = NI_msub(rPS0(inst.FA), c_value, rPS0(inst.FB));
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
{
const double result = ForceSingle(product.value);
rPS0(inst.FD) = rPS1(inst.FD) = result;
PowerPC::UpdateFPRF(result);
}
if (inst.Rc)
Helper_UpdateCR1();
@ -486,9 +549,14 @@ void Interpreter::fmsubsx(UGeckoInstruction inst)
void Interpreter::fnmaddx(UGeckoInstruction inst)
{
double result = ForceDouble(NI_madd(rPS0(inst.FA), rPS0(inst.FC), rPS0(inst.FB)));
rPS0(inst.FD) = std::isnan(result) ? result : -result;
PowerPC::UpdateFPRF(rPS0(inst.FD));
const FPResult product = NI_madd(rPS0(inst.FA), rPS0(inst.FC), rPS0(inst.FB));
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
{
const double result = ForceDouble(product.value);
rPS0(inst.FD) = std::isnan(result) ? result : -result;
PowerPC::UpdateFPRF(rPS0(inst.FD));
}
if (inst.Rc)
Helper_UpdateCR1();
@ -496,10 +564,15 @@ void Interpreter::fnmaddx(UGeckoInstruction inst)
void Interpreter::fnmaddsx(UGeckoInstruction inst)
{
double c_value = Force25Bit(rPS0(inst.FC));
double result = ForceSingle(NI_madd(rPS0(inst.FA), c_value, rPS0(inst.FB)));
rPS0(inst.FD) = rPS1(inst.FD) = std::isnan(result) ? result : -result;
PowerPC::UpdateFPRF(rPS0(inst.FD));
const double c_value = Force25Bit(rPS0(inst.FC));
const FPResult product = NI_madd(rPS0(inst.FA), c_value, rPS0(inst.FB));
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
{
const double result = ForceSingle(product.value);
rPS0(inst.FD) = rPS1(inst.FD) = std::isnan(result) ? result : -result;
PowerPC::UpdateFPRF(rPS0(inst.FD));
}
if (inst.Rc)
Helper_UpdateCR1();
@ -507,9 +580,14 @@ void Interpreter::fnmaddsx(UGeckoInstruction inst)
void Interpreter::fnmsubx(UGeckoInstruction inst)
{
double result = ForceDouble(NI_msub(rPS0(inst.FA), rPS0(inst.FC), rPS0(inst.FB)));
rPS0(inst.FD) = std::isnan(result) ? result : -result;
PowerPC::UpdateFPRF(rPS0(inst.FD));
const FPResult product = NI_msub(rPS0(inst.FA), rPS0(inst.FC), rPS0(inst.FB));
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
{
const double result = ForceDouble(product.value);
rPS0(inst.FD) = std::isnan(result) ? result : -result;
PowerPC::UpdateFPRF(rPS0(inst.FD));
}
if (inst.Rc)
Helper_UpdateCR1();
@ -517,10 +595,15 @@ void Interpreter::fnmsubx(UGeckoInstruction inst)
void Interpreter::fnmsubsx(UGeckoInstruction inst)
{
double c_value = Force25Bit(rPS0(inst.FC));
double result = ForceSingle(NI_msub(rPS0(inst.FA), c_value, rPS0(inst.FB)));
rPS0(inst.FD) = rPS1(inst.FD) = std::isnan(result) ? result : -result;
PowerPC::UpdateFPRF(rPS0(inst.FD));
const double c_value = Force25Bit(rPS0(inst.FC));
const FPResult product = NI_msub(rPS0(inst.FA), c_value, rPS0(inst.FB));
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
{
const double result = ForceSingle(product.value);
rPS0(inst.FD) = rPS1(inst.FD) = std::isnan(result) ? result : -result;
PowerPC::UpdateFPRF(rPS0(inst.FD));
}
if (inst.Rc)
Helper_UpdateCR1();
@ -528,8 +611,14 @@ void Interpreter::fnmsubsx(UGeckoInstruction inst)
void Interpreter::fsubx(UGeckoInstruction inst)
{
rPS0(inst.FD) = ForceDouble(NI_sub(rPS0(inst.FA), rPS0(inst.FB)));
PowerPC::UpdateFPRF(rPS0(inst.FD));
const FPResult difference = NI_sub(rPS0(inst.FA), rPS0(inst.FB));
if (FPSCR.VE == 0 || difference.HasNoInvalidExceptions())
{
const double result = ForceDouble(difference.value);
rPS0(inst.FD) = result;
PowerPC::UpdateFPRF(result);
}
if (inst.Rc)
Helper_UpdateCR1();
@ -537,8 +626,14 @@ void Interpreter::fsubx(UGeckoInstruction inst)
void Interpreter::fsubsx(UGeckoInstruction inst)
{
rPS0(inst.FD) = rPS1(inst.FD) = ForceSingle(NI_sub(rPS0(inst.FA), rPS0(inst.FB)));
PowerPC::UpdateFPRF(rPS0(inst.FD));
const FPResult difference = NI_sub(rPS0(inst.FA), rPS0(inst.FB));
if (FPSCR.VE == 0 || difference.HasNoInvalidExceptions())
{
const double result = ForceSingle(difference.value);
rPS0(inst.FD) = rPS1(inst.FD) = result;
PowerPC::UpdateFPRF(result);
}
if (inst.Rc)
Helper_UpdateCR1();

View File

@ -104,8 +104,8 @@ void Interpreter::ps_merge11(UGeckoInstruction inst)
// From here on, the real deal.
void Interpreter::ps_div(UGeckoInstruction inst)
{
rPS0(inst.FD) = ForceSingle(NI_div(rPS0(inst.FA), rPS0(inst.FB)));
rPS1(inst.FD) = ForceSingle(NI_div(rPS1(inst.FA), rPS1(inst.FB)));
rPS0(inst.FD) = ForceSingle(NI_div(rPS0(inst.FA), rPS0(inst.FB)).value);
rPS1(inst.FD) = ForceSingle(NI_div(rPS1(inst.FA), rPS1(inst.FB)).value);
PowerPC::UpdateFPRF(rPS0(inst.FD));
if (inst.Rc)
@ -172,8 +172,8 @@ void Interpreter::ps_rsqrte(UGeckoInstruction inst)
void Interpreter::ps_sub(UGeckoInstruction inst)
{
rPS0(inst.FD) = ForceSingle(NI_sub(rPS0(inst.FA), rPS0(inst.FB)));
rPS1(inst.FD) = ForceSingle(NI_sub(rPS1(inst.FA), rPS1(inst.FB)));
rPS0(inst.FD) = ForceSingle(NI_sub(rPS0(inst.FA), rPS0(inst.FB)).value);
rPS1(inst.FD) = ForceSingle(NI_sub(rPS1(inst.FA), rPS1(inst.FB)).value);
PowerPC::UpdateFPRF(rPS0(inst.FD));
if (inst.Rc)
@ -182,8 +182,8 @@ void Interpreter::ps_sub(UGeckoInstruction inst)
void Interpreter::ps_add(UGeckoInstruction inst)
{
rPS0(inst.FD) = ForceSingle(NI_add(rPS0(inst.FA), rPS0(inst.FB)));
rPS1(inst.FD) = ForceSingle(NI_add(rPS1(inst.FA), rPS1(inst.FB)));
rPS0(inst.FD) = ForceSingle(NI_add(rPS0(inst.FA), rPS0(inst.FB)).value);
rPS1(inst.FD) = ForceSingle(NI_add(rPS1(inst.FA), rPS1(inst.FB)).value);
PowerPC::UpdateFPRF(rPS0(inst.FD));
if (inst.Rc)
@ -192,10 +192,10 @@ void Interpreter::ps_add(UGeckoInstruction inst)
void Interpreter::ps_mul(UGeckoInstruction inst)
{
double c0 = Force25Bit(rPS0(inst.FC));
double c1 = Force25Bit(rPS1(inst.FC));
rPS0(inst.FD) = ForceSingle(NI_mul(rPS0(inst.FA), c0));
rPS1(inst.FD) = ForceSingle(NI_mul(rPS1(inst.FA), c1));
const double c0 = Force25Bit(rPS0(inst.FC));
const double c1 = Force25Bit(rPS1(inst.FC));
rPS0(inst.FD) = ForceSingle(NI_mul(rPS0(inst.FA), c0).value);
rPS1(inst.FD) = ForceSingle(NI_mul(rPS1(inst.FA), c1).value);
PowerPC::UpdateFPRF(rPS0(inst.FD));
if (inst.Rc)
@ -204,10 +204,10 @@ void Interpreter::ps_mul(UGeckoInstruction inst)
void Interpreter::ps_msub(UGeckoInstruction inst)
{
double c0 = Force25Bit(rPS0(inst.FC));
double c1 = Force25Bit(rPS1(inst.FC));
rPS0(inst.FD) = ForceSingle(NI_msub(rPS0(inst.FA), c0, rPS0(inst.FB)));
rPS1(inst.FD) = ForceSingle(NI_msub(rPS1(inst.FA), c1, rPS1(inst.FB)));
const double c0 = Force25Bit(rPS0(inst.FC));
const double c1 = Force25Bit(rPS1(inst.FC));
rPS0(inst.FD) = ForceSingle(NI_msub(rPS0(inst.FA), c0, rPS0(inst.FB)).value);
rPS1(inst.FD) = ForceSingle(NI_msub(rPS1(inst.FA), c1, rPS1(inst.FB)).value);
PowerPC::UpdateFPRF(rPS0(inst.FD));
if (inst.Rc)
@ -216,10 +216,10 @@ void Interpreter::ps_msub(UGeckoInstruction inst)
void Interpreter::ps_madd(UGeckoInstruction inst)
{
double c0 = Force25Bit(rPS0(inst.FC));
double c1 = Force25Bit(rPS1(inst.FC));
rPS0(inst.FD) = ForceSingle(NI_madd(rPS0(inst.FA), c0, rPS0(inst.FB)));
rPS1(inst.FD) = ForceSingle(NI_madd(rPS1(inst.FA), c1, rPS1(inst.FB)));
const double c0 = Force25Bit(rPS0(inst.FC));
const double c1 = Force25Bit(rPS1(inst.FC));
rPS0(inst.FD) = ForceSingle(NI_madd(rPS0(inst.FA), c0, rPS0(inst.FB)).value);
rPS1(inst.FD) = ForceSingle(NI_madd(rPS1(inst.FA), c1, rPS1(inst.FB)).value);
PowerPC::UpdateFPRF(rPS0(inst.FD));
if (inst.Rc)
@ -228,10 +228,10 @@ void Interpreter::ps_madd(UGeckoInstruction inst)
void Interpreter::ps_nmsub(UGeckoInstruction inst)
{
double c0 = Force25Bit(rPS0(inst.FC));
double c1 = Force25Bit(rPS1(inst.FC));
double result0 = ForceSingle(NI_msub(rPS0(inst.FA), c0, rPS0(inst.FB)));
double result1 = ForceSingle(NI_msub(rPS1(inst.FA), c1, rPS1(inst.FB)));
const double c0 = Force25Bit(rPS0(inst.FC));
const double c1 = Force25Bit(rPS1(inst.FC));
const double result0 = ForceSingle(NI_msub(rPS0(inst.FA), c0, rPS0(inst.FB)).value);
const double result1 = ForceSingle(NI_msub(rPS1(inst.FA), c1, rPS1(inst.FB)).value);
rPS0(inst.FD) = std::isnan(result0) ? result0 : -result0;
rPS1(inst.FD) = std::isnan(result1) ? result1 : -result1;
PowerPC::UpdateFPRF(rPS0(inst.FD));
@ -242,10 +242,10 @@ void Interpreter::ps_nmsub(UGeckoInstruction inst)
void Interpreter::ps_nmadd(UGeckoInstruction inst)
{
double c0 = Force25Bit(rPS0(inst.FC));
double c1 = Force25Bit(rPS1(inst.FC));
double result0 = ForceSingle(NI_madd(rPS0(inst.FA), c0, rPS0(inst.FB)));
double result1 = ForceSingle(NI_madd(rPS1(inst.FA), c1, rPS1(inst.FB)));
const double c0 = Force25Bit(rPS0(inst.FC));
const double c1 = Force25Bit(rPS1(inst.FC));
const double result0 = ForceSingle(NI_madd(rPS0(inst.FA), c0, rPS0(inst.FB)).value);
const double result1 = ForceSingle(NI_madd(rPS1(inst.FA), c1, rPS1(inst.FB)).value);
rPS0(inst.FD) = std::isnan(result0) ? result0 : -result0;
rPS1(inst.FD) = std::isnan(result1) ? result1 : -result1;
PowerPC::UpdateFPRF(rPS0(inst.FD));
@ -256,8 +256,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));
const double p0 = ForceSingle(NI_add(rPS0(inst.FA), rPS1(inst.FB)).value);
const double p1 = ForceSingle(rPS1(inst.FC));
rPS0(inst.FD) = p0;
rPS1(inst.FD) = p1;
PowerPC::UpdateFPRF(rPS0(inst.FD));
@ -268,8 +268,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)));
const double p0 = ForceSingle(rPS0(inst.FC));
const double p1 = ForceSingle(NI_add(rPS0(inst.FA), rPS1(inst.FB)).value);
rPS0(inst.FD) = p0;
rPS1(inst.FD) = p1;
PowerPC::UpdateFPRF(rPS1(inst.FD));
@ -280,9 +280,9 @@ 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));
const double c0 = Force25Bit(rPS0(inst.FC));
const double p0 = ForceSingle(NI_mul(rPS0(inst.FA), c0).value);
const double p1 = ForceSingle(NI_mul(rPS1(inst.FA), c0).value);
rPS0(inst.FD) = p0;
rPS1(inst.FD) = p1;
PowerPC::UpdateFPRF(rPS0(inst.FD));
@ -293,9 +293,9 @@ 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));
const double c1 = Force25Bit(rPS1(inst.FC));
const double p0 = ForceSingle(NI_mul(rPS0(inst.FA), c1).value);
const double p1 = ForceSingle(NI_mul(rPS1(inst.FA), c1).value);
rPS0(inst.FD) = p0;
rPS1(inst.FD) = p1;
PowerPC::UpdateFPRF(rPS0(inst.FD));
@ -306,9 +306,9 @@ 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)));
const double c0 = Force25Bit(rPS0(inst.FC));
const double p0 = ForceSingle(NI_madd(rPS0(inst.FA), c0, rPS0(inst.FB)).value);
const double p1 = ForceSingle(NI_madd(rPS1(inst.FA), c0, rPS1(inst.FB)).value);
rPS0(inst.FD) = p0;
rPS1(inst.FD) = p1;
PowerPC::UpdateFPRF(rPS0(inst.FD));
@ -319,9 +319,9 @@ 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)));
const double c1 = Force25Bit(rPS1(inst.FC));
const double p0 = ForceSingle(NI_madd(rPS0(inst.FA), c1, rPS0(inst.FB)).value);
const double p1 = ForceSingle(NI_madd(rPS1(inst.FA), c1, rPS1(inst.FB)).value);
rPS0(inst.FD) = p0;
rPS1(inst.FD) = p1;
PowerPC::UpdateFPRF(rPS0(inst.FD));