Interpreter: Use std::fma for emulating FMA

This is more accurate to the original hardware's rounding behavior.
This commit is contained in:
JosJuice 2021-05-23 21:15:07 +02:00
parent ff08b85740
commit 9bc5bd83a9
1 changed files with 4 additions and 44 deletions

View File

@ -238,7 +238,7 @@ inline FPResult NI_sub(UReg_FPSCR* fpscr, double a, double b)
// inputs are checked for NaN is still a, b, c. // inputs are checked for NaN is still a, b, c.
inline FPResult NI_madd(UReg_FPSCR* fpscr, double a, double c, double b) inline FPResult NI_madd(UReg_FPSCR* fpscr, double a, double c, double b)
{ {
FPResult result{a * c}; FPResult result{std::fma(a, c, b)};
if (std::isnan(result.value)) if (std::isnan(result.value))
{ {
@ -263,27 +263,7 @@ inline FPResult NI_madd(UReg_FPSCR* fpscr, double a, double c, double b)
return result; return result;
} }
result.SetException(fpscr, FPSCR_VXIMZ); result.SetException(fpscr, std::isnan(a * c) ? FPSCR_VXIMZ : FPSCR_VXISI);
result.value = PPC_NAN;
return result;
}
result.value += b;
if (std::isnan(result.value))
{
if (Common::IsSNAN(b))
result.SetException(fpscr, FPSCR_VXSNAN);
fpscr->ClearFIFR();
if (std::isnan(b))
{
result.value = MakeQuiet(b);
return result;
}
result.SetException(fpscr, FPSCR_VXISI);
result.value = PPC_NAN; result.value = PPC_NAN;
return result; return result;
} }
@ -296,7 +276,7 @@ inline FPResult NI_madd(UReg_FPSCR* fpscr, double a, double c, double b)
inline FPResult NI_msub(UReg_FPSCR* fpscr, double a, double c, double b) inline FPResult NI_msub(UReg_FPSCR* fpscr, double a, double c, double b)
{ {
FPResult result{a * c}; FPResult result{std::fma(a, c, -b)};
if (std::isnan(result.value)) if (std::isnan(result.value))
{ {
@ -321,27 +301,7 @@ inline FPResult NI_msub(UReg_FPSCR* fpscr, double a, double c, double b)
return result; return result;
} }
result.SetException(fpscr, FPSCR_VXIMZ); result.SetException(fpscr, std::isnan(a * c) ? FPSCR_VXIMZ : FPSCR_VXISI);
result.value = PPC_NAN;
return result;
}
result.value -= b;
if (std::isnan(result.value))
{
if (Common::IsSNAN(b))
result.SetException(fpscr, FPSCR_VXSNAN);
fpscr->ClearFIFR();
if (std::isnan(b))
{
result.value = MakeQuiet(b);
return result;
}
result.SetException(fpscr, FPSCR_VXISI);
result.value = PPC_NAN; result.value = PPC_NAN;
return result; return result;
} }