Interpreter: fix rounding of FNMA instructions
x86: round(-a*c +/- b) PowerPC: -round(a*c +/- b) If the rounding mode is set to +/- infinity, the order of round/negate matters.
This commit is contained in:
parent
8beb67fd3e
commit
bcdafc7e34
|
@ -150,7 +150,7 @@ inline double NI_sub(double a, double b)
|
||||||
// FMA instructions on PowerPC are weird:
|
// FMA instructions on PowerPC are weird:
|
||||||
// They calculate (a * c) + b, but the order in which
|
// They calculate (a * c) + b, but the order in which
|
||||||
// inputs are checked for NaN is still a, b, c.
|
// inputs are checked for NaN is still a, b, c.
|
||||||
inline double NI_madd(double a, double c, double b, bool negate = false)
|
inline double NI_madd(double a, double c, double b)
|
||||||
{
|
{
|
||||||
double t = a * c;
|
double t = a * c;
|
||||||
if (std::isnan(t))
|
if (std::isnan(t))
|
||||||
|
@ -168,10 +168,10 @@ inline double NI_madd(double a, double c, double b, bool negate = false)
|
||||||
SetFPException(FPSCR_VXISI);
|
SetFPException(FPSCR_VXISI);
|
||||||
return PPC_NAN;
|
return PPC_NAN;
|
||||||
}
|
}
|
||||||
return negate ? -t : t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline double NI_msub(double a, double c, double b, bool negate = false)
|
inline double NI_msub(double a, double c, double b)
|
||||||
{
|
{
|
||||||
double t = a * c;
|
double t = a * c;
|
||||||
if (std::isnan(t))
|
if (std::isnan(t))
|
||||||
|
@ -190,7 +190,7 @@ inline double NI_msub(double a, double c, double b, bool negate = false)
|
||||||
SetFPException(FPSCR_VXISI);
|
SetFPException(FPSCR_VXISI);
|
||||||
return PPC_NAN;
|
return PPC_NAN;
|
||||||
}
|
}
|
||||||
return negate ? -t : t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
// used by stfsXX instructions and ps_rsqrte
|
// used by stfsXX instructions and ps_rsqrte
|
||||||
|
|
|
@ -425,7 +425,8 @@ void Interpreter::fmsubsx(UGeckoInstruction _inst)
|
||||||
|
|
||||||
void Interpreter::fnmaddx(UGeckoInstruction _inst)
|
void Interpreter::fnmaddx(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
rPS0(_inst.FD) = ForceDouble(NI_madd(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB), true));
|
double result = ForceDouble(NI_madd(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB)));
|
||||||
|
rPS0(_inst.FD) = std::isnan(result) ? result : -result;
|
||||||
UpdateFPRF(rPS0(_inst.FD));
|
UpdateFPRF(rPS0(_inst.FD));
|
||||||
|
|
||||||
if (_inst.Rc)
|
if (_inst.Rc)
|
||||||
|
@ -435,7 +436,8 @@ void Interpreter::fnmaddx(UGeckoInstruction _inst)
|
||||||
void Interpreter::fnmaddsx(UGeckoInstruction _inst)
|
void Interpreter::fnmaddsx(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
double c_value = Force25Bit(rPS0(_inst.FC));
|
double c_value = Force25Bit(rPS0(_inst.FC));
|
||||||
rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_madd(rPS0(_inst.FA), c_value, rPS0(_inst.FB), true));
|
double result = ForceSingle(NI_madd(rPS0(_inst.FA), c_value, rPS0(_inst.FB)));
|
||||||
|
rPS0(_inst.FD) = rPS1(_inst.FD) = std::isnan(result) ? result : -result;
|
||||||
UpdateFPRF(rPS0(_inst.FD));
|
UpdateFPRF(rPS0(_inst.FD));
|
||||||
|
|
||||||
if (_inst.Rc)
|
if (_inst.Rc)
|
||||||
|
@ -444,7 +446,8 @@ void Interpreter::fnmaddsx(UGeckoInstruction _inst)
|
||||||
|
|
||||||
void Interpreter::fnmsubx(UGeckoInstruction _inst)
|
void Interpreter::fnmsubx(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
rPS0(_inst.FD) = ForceDouble(NI_msub(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB), true));
|
double result = ForceDouble(NI_msub(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB)));
|
||||||
|
rPS0(_inst.FD) = std::isnan(result) ? result : -result;
|
||||||
UpdateFPRF(rPS0(_inst.FD));
|
UpdateFPRF(rPS0(_inst.FD));
|
||||||
|
|
||||||
if (_inst.Rc)
|
if (_inst.Rc)
|
||||||
|
@ -454,7 +457,8 @@ void Interpreter::fnmsubx(UGeckoInstruction _inst)
|
||||||
void Interpreter::fnmsubsx(UGeckoInstruction _inst)
|
void Interpreter::fnmsubsx(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
double c_value = Force25Bit(rPS0(_inst.FC));
|
double c_value = Force25Bit(rPS0(_inst.FC));
|
||||||
rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_msub(rPS0(_inst.FA), c_value, rPS0(_inst.FB), true));
|
double result = ForceSingle(NI_msub(rPS0(_inst.FA), c_value, rPS0(_inst.FB)));
|
||||||
|
rPS0(_inst.FD) = rPS1(_inst.FD) = std::isnan(result) ? result : -result;
|
||||||
UpdateFPRF(rPS0(_inst.FD));
|
UpdateFPRF(rPS0(_inst.FD));
|
||||||
|
|
||||||
if (_inst.Rc)
|
if (_inst.Rc)
|
||||||
|
|
|
@ -214,8 +214,10 @@ void Interpreter::ps_nmsub(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
double c0 = Force25Bit(rPS0(_inst.FC));
|
double c0 = Force25Bit(rPS0(_inst.FC));
|
||||||
double c1 = Force25Bit(rPS1(_inst.FC));
|
double c1 = Force25Bit(rPS1(_inst.FC));
|
||||||
rPS0(_inst.FD) = ForceSingle(NI_msub(rPS0(_inst.FA), c0, rPS0(_inst.FB), true));
|
double result0 = ForceSingle(NI_msub(rPS0(_inst.FA), c0, rPS0(_inst.FB)));
|
||||||
rPS1(_inst.FD) = ForceSingle(NI_msub(rPS1(_inst.FA), c1, rPS1(_inst.FB), true));
|
double result1 = ForceSingle(NI_msub(rPS1(_inst.FA), c1, rPS1(_inst.FB)));
|
||||||
|
rPS0(_inst.FD) = std::isnan(result0) ? result0 : -result0;
|
||||||
|
rPS1(_inst.FD) = std::isnan(result1) ? result1 : -result1;
|
||||||
UpdateFPRF(rPS0(_inst.FD));
|
UpdateFPRF(rPS0(_inst.FD));
|
||||||
|
|
||||||
if (_inst.Rc)
|
if (_inst.Rc)
|
||||||
|
@ -226,8 +228,10 @@ void Interpreter::ps_nmadd(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
double c0 = Force25Bit(rPS0(_inst.FC));
|
double c0 = Force25Bit(rPS0(_inst.FC));
|
||||||
double c1 = Force25Bit(rPS1(_inst.FC));
|
double c1 = Force25Bit(rPS1(_inst.FC));
|
||||||
rPS0(_inst.FD) = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB), true));
|
double result0 = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB)));
|
||||||
rPS1(_inst.FD) = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB), true));
|
double result1 = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB)));
|
||||||
|
rPS0(_inst.FD) = std::isnan(result0) ? result0 : -result0;
|
||||||
|
rPS1(_inst.FD) = std::isnan(result1) ? result1 : -result1;
|
||||||
UpdateFPRF(rPS0(_inst.FD));
|
UpdateFPRF(rPS0(_inst.FD));
|
||||||
|
|
||||||
if (_inst.Rc)
|
if (_inst.Rc)
|
||||||
|
|
Loading…
Reference in New Issue