Skip to content
Permalink
Browse files
Merge pull request #9811 from JosJuice/fprf-denormal-singles
Fix FPRF handling of denormal singles
  • Loading branch information
Tilka committed Jun 29, 2021
2 parents 856c82a + ccd8233 commit 901a4fb
Show file tree
Hide file tree
Showing 13 changed files with 224 additions and 194 deletions.
@@ -87,7 +87,6 @@ enum PPCFpClass
// Uses PowerPC conventions for the return value, so it can be easily
// used directly in CPU emulation.
u32 ClassifyDouble(double dvalue);
// More efficient float version.
u32 ClassifyFloat(float fvalue);

struct BaseAndDec
@@ -36,15 +36,13 @@ inline void SetFPException(UReg_FPSCR* fpscr, u32 mask)
fpscr->VX = (fpscr->Hex & FPSCR_VX_ANY) != 0;
}

inline double ForceSingle(const UReg_FPSCR& fpscr, double value)
inline float ForceSingle(const UReg_FPSCR& fpscr, double value)
{
// convert to float...
float x = (float)value;
float x = static_cast<float>(value);
if (!cpu_info.bFlushToZero && fpscr.NI)
{
x = Common::FlushToZero(x);
}
// ...and back to double:
return x;
}

@@ -290,7 +290,7 @@ void Interpreter::fselx(UGeckoInstruction inst)
void Interpreter::frspx(UGeckoInstruction inst) // round to single
{
const double b = rPS(inst.FB).PS0AsDouble();
const double rounded = ForceSingle(FPSCR, b);
const float rounded = ForceSingle(FPSCR, b);

if (std::isnan(b))
{
@@ -302,7 +302,7 @@ void Interpreter::frspx(UGeckoInstruction inst) // round to single
if (!is_snan || FPSCR.VE == 0)
{
rPS(inst.FD).Fill(rounded);
PowerPC::UpdateFPRF(b);
PowerPC::UpdateFPRFSingle(rounded);
}

FPSCR.ClearFIFR();
@@ -311,7 +311,7 @@ void Interpreter::frspx(UGeckoInstruction inst) // round to single
{
SetFI(&FPSCR, b != rounded);
FPSCR.FR = fabs(rounded) > fabs(b);
PowerPC::UpdateFPRF(rounded);
PowerPC::UpdateFPRFSingle(rounded);
rPS(inst.FD).Fill(rounded);
}

@@ -333,7 +333,7 @@ void Interpreter::fmulx(UGeckoInstruction inst)
rPS(inst.FD).SetPS0(result);
FPSCR.FI = 0; // are these flags important?
FPSCR.FR = 0;
PowerPC::UpdateFPRF(result);
PowerPC::UpdateFPRFDouble(result);
}

if (inst.Rc)
@@ -349,12 +349,12 @@ void Interpreter::fmulsx(UGeckoInstruction inst)

if (FPSCR.VE == 0 || d_value.HasNoInvalidExceptions())
{
const double result = ForceSingle(FPSCR, d_value.value);
const float result = ForceSingle(FPSCR, d_value.value);

rPS(inst.FD).Fill(result);
FPSCR.FI = 0;
FPSCR.FR = 0;
PowerPC::UpdateFPRF(result);
PowerPC::UpdateFPRFSingle(result);
}

if (inst.Rc)
@@ -372,7 +372,7 @@ void Interpreter::fmaddx(UGeckoInstruction inst)
{
const double result = ForceDouble(FPSCR, product.value);
rPS(inst.FD).SetPS0(result);
PowerPC::UpdateFPRF(result);
PowerPC::UpdateFPRFDouble(result);
}

if (inst.Rc)
@@ -390,12 +390,12 @@ void Interpreter::fmaddsx(UGeckoInstruction inst)

if (FPSCR.VE == 0 || d_value.HasNoInvalidExceptions())
{
const double result = ForceSingle(FPSCR, d_value.value);
const float result = ForceSingle(FPSCR, d_value.value);

rPS(inst.FD).Fill(result);
FPSCR.FI = d_value.value != result;
FPSCR.FR = 0;
PowerPC::UpdateFPRF(result);
PowerPC::UpdateFPRFSingle(result);
}

if (inst.Rc)
@@ -413,7 +413,7 @@ void Interpreter::faddx(UGeckoInstruction inst)
{
const double result = ForceDouble(FPSCR, sum.value);
rPS(inst.FD).SetPS0(result);
PowerPC::UpdateFPRF(result);
PowerPC::UpdateFPRFDouble(result);
}

if (inst.Rc)
@@ -428,9 +428,9 @@ void Interpreter::faddsx(UGeckoInstruction inst)

if (FPSCR.VE == 0 || sum.HasNoInvalidExceptions())
{
const double result = ForceSingle(FPSCR, sum.value);
const float result = ForceSingle(FPSCR, sum.value);
rPS(inst.FD).Fill(result);
PowerPC::UpdateFPRF(result);
PowerPC::UpdateFPRFSingle(result);
}

if (inst.Rc)
@@ -450,7 +450,7 @@ void Interpreter::fdivx(UGeckoInstruction inst)
{
const double result = ForceDouble(FPSCR, quotient.value);
rPS(inst.FD).SetPS0(result);
PowerPC::UpdateFPRF(result);
PowerPC::UpdateFPRFDouble(result);
}

// FR,FI,OX,UX???
@@ -468,9 +468,9 @@ void Interpreter::fdivsx(UGeckoInstruction inst)

if (not_divide_by_zero && not_invalid)
{
const double result = ForceSingle(FPSCR, quotient.value);
const float result = ForceSingle(FPSCR, quotient.value);
rPS(inst.FD).Fill(result);
PowerPC::UpdateFPRF(result);
PowerPC::UpdateFPRFSingle(result);
}

if (inst.Rc)
@@ -485,7 +485,7 @@ void Interpreter::fresx(UGeckoInstruction inst)
const auto compute_result = [inst](double value) {
const double result = Common::ApproximateReciprocal(value);
rPS(inst.FD).Fill(result);
PowerPC::UpdateFPRF(result);
PowerPC::UpdateFPRFSingle(result);
};

if (b == 0.0)
@@ -523,7 +523,7 @@ void Interpreter::frsqrtex(UGeckoInstruction inst)
const auto compute_result = [inst](double value) {
const double result = Common::ApproximateReciprocalSquareRoot(value);
rPS(inst.FD).SetPS0(result);
PowerPC::UpdateFPRF(result);
PowerPC::UpdateFPRFDouble(result);
};

if (b < 0.0)
@@ -574,7 +574,7 @@ void Interpreter::fmsubx(UGeckoInstruction inst)
{
const double result = ForceDouble(FPSCR, product.value);
rPS(inst.FD).SetPS0(result);
PowerPC::UpdateFPRF(result);
PowerPC::UpdateFPRFDouble(result);
}

if (inst.Rc)
@@ -592,9 +592,9 @@ void Interpreter::fmsubsx(UGeckoInstruction inst)

if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
{
const double result = ForceSingle(FPSCR, product.value);
const float result = ForceSingle(FPSCR, product.value);
rPS(inst.FD).Fill(result);
PowerPC::UpdateFPRF(result);
PowerPC::UpdateFPRFSingle(result);
}

if (inst.Rc)
@@ -615,7 +615,7 @@ void Interpreter::fnmaddx(UGeckoInstruction inst)
const double result = std::isnan(tmp) ? tmp : -tmp;

rPS(inst.FD).SetPS0(result);
PowerPC::UpdateFPRF(result);
PowerPC::UpdateFPRFDouble(result);
}

if (inst.Rc)
@@ -633,11 +633,11 @@ void Interpreter::fnmaddsx(UGeckoInstruction inst)

if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
{
const double tmp = ForceSingle(FPSCR, product.value);
const double result = std::isnan(tmp) ? tmp : -tmp;
const float tmp = ForceSingle(FPSCR, product.value);
const float result = std::isnan(tmp) ? tmp : -tmp;

rPS(inst.FD).Fill(result);
PowerPC::UpdateFPRF(result);
PowerPC::UpdateFPRFSingle(result);
}

if (inst.Rc)
@@ -658,7 +658,7 @@ void Interpreter::fnmsubx(UGeckoInstruction inst)
const double result = std::isnan(tmp) ? tmp : -tmp;

rPS(inst.FD).SetPS0(result);
PowerPC::UpdateFPRF(result);
PowerPC::UpdateFPRFDouble(result);
}

if (inst.Rc)
@@ -676,11 +676,11 @@ void Interpreter::fnmsubsx(UGeckoInstruction inst)

if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
{
const double tmp = ForceSingle(FPSCR, product.value);
const double result = std::isnan(tmp) ? tmp : -tmp;
const float tmp = ForceSingle(FPSCR, product.value);
const float result = std::isnan(tmp) ? tmp : -tmp;

rPS(inst.FD).Fill(result);
PowerPC::UpdateFPRF(result);
PowerPC::UpdateFPRFSingle(result);
}

if (inst.Rc)
@@ -698,7 +698,7 @@ void Interpreter::fsubx(UGeckoInstruction inst)
{
const double result = ForceDouble(FPSCR, difference.value);
rPS(inst.FD).SetPS0(result);
PowerPC::UpdateFPRF(result);
PowerPC::UpdateFPRFDouble(result);
}

if (inst.Rc)
@@ -714,9 +714,9 @@ void Interpreter::fsubsx(UGeckoInstruction inst)

if (FPSCR.VE == 0 || difference.HasNoInvalidExceptions())
{
const double result = ForceSingle(FPSCR, difference.value);
const float result = ForceSingle(FPSCR, difference.value);
rPS(inst.FD).Fill(result);
PowerPC::UpdateFPRF(result);
PowerPC::UpdateFPRFSingle(result);
}

if (inst.Rc)

0 comments on commit 901a4fb

Please sign in to comment.