Skip to content

Commit

Permalink
x86jit: Force INF * 0 to +NAN.
Browse files Browse the repository at this point in the history
See #12519 - this is needed for some graphics to render properly.  Seems
to already happen on ARM, so no change to armjit.
  • Loading branch information
unknownbrackets committed Apr 5, 2020
1 parent 350589d commit d5e1943
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 3 deletions.
6 changes: 5 additions & 1 deletion Core/MIPS/IR/IRInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,11 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) {
mips->f[inst->dest] = mips->f[inst->src1] - mips->f[inst->src2];
break;
case IROp::FMul:
mips->f[inst->dest] = mips->f[inst->src1] * mips->f[inst->src2];
if ((my_isinf(mips->f[inst->src1]) && mips->f[inst->src2] == 0.0f) || (mips->f[inst->src1] == 0.0f && my_isinf(mips->f[inst->src2]))) {
mips->fi[inst->dest] = 0x7fc00000;
} else {
mips->f[inst->dest] = mips->f[inst->src1] * mips->f[inst->src2];
}
break;
case IROp::FDiv:
mips->f[inst->dest] = mips->f[inst->src1] / mips->f[inst->src2];
Expand Down
9 changes: 8 additions & 1 deletion Core/MIPS/MIPSInt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -974,7 +974,14 @@ namespace MIPSInt
{
case 0: F(fd) = F(fs) + F(ft); break; // add.s
case 1: F(fd) = F(fs) - F(ft); break; // sub.s
case 2: F(fd) = F(fs) * F(ft); break; // mul.s
case 2: // mul.s
if ((my_isinf(F(fs)) && F(ft) == 0.0f) || (F(fs) == 0.0f && my_isinf(F(ft)))) {
// Must be positive NAN, see #12519.
FI(fd) = 0x7fc00000;
} else {
F(fd) = F(fs) * F(ft);
}
break;
case 3: F(fd) = F(fs) / F(ft); break; // div.s
default:
_dbg_assert_msg_(CPU,0,"Trying to interpret FPU3Op instruction that can't be interpreted");
Expand Down
25 changes: 24 additions & 1 deletion Core/MIPS/x86/CompFPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ namespace MIPSComp {
using namespace Gen;
using namespace X64JitConstants;

alignas(16) const u32 reverseQNAN[4] = { 0x803FFFFF, 0x803FFFFF, 0x803FFFFF, 0x803FFFFF };

void Jit::CopyFPReg(X64Reg dst, OpArg src) {
if (src.IsSimpleReg()) {
MOVAPS(dst, src);
Expand Down Expand Up @@ -90,7 +92,28 @@ void Jit::Comp_FPU3op(MIPSOpcode op) {
switch (op & 0x3f) {
case 0: CompFPTriArith(op, &XEmitter::ADDSS, false); break; //F(fd) = F(fs) + F(ft); //add
case 1: CompFPTriArith(op, &XEmitter::SUBSS, true); break; //F(fd) = F(fs) - F(ft); //sub
case 2: CompFPTriArith(op, &XEmitter::MULSS, false); break; //F(fd) = F(fs) * F(ft); //mul
case 2: //F(fd) = F(fs) * F(ft); //mul
// XMM1 = !my_isnan(fs) && !my_isnan(ft)
MOVSS(XMM1, fpr.R(_FS));
CMPORDSS(XMM1, fpr.R(_FT));
CompFPTriArith(op, &XEmitter::MULSS, false);

// fd must still be in a reg, save it in XMM0 for now.
MOVAPS(XMM0, fpr.R(_FD));
// fd = my_isnan(fd) && !my_isnan(fs) && !my_isnan(ft)
CMPUNORDSS(fpr.RX(_FD), fpr.R(_FD));
ANDPS(fpr.RX(_FD), R(XMM1));
// At this point fd = FFFFFFFF if non-NAN inputs produced a NAN output.
// We'll AND it with the inverse QNAN bits to clear (00000000 means no change.)
if (RipAccessible(&reverseQNAN)) {
ANDPS(fpr.RX(_FD), M(&reverseQNAN)); // rip accessible
} else {
MOV(PTRBITS, R(TEMPREG), ImmPtr(&reverseQNAN));
ANDPS(fpr.RX(_FD), MatR(TEMPREG));
}
// ANDN is backwards, which is why we saved XMM0 to start. Now put it back.
ANDNPS(fpr.RX(_FD), R(XMM0));
break;
case 3: CompFPTriArith(op, &XEmitter::DIVSS, true); break; //F(fd) = F(fs) / F(ft); //div
default:
_dbg_assert_msg_(CPU,0,"Trying to compile FPU3Op instruction that can't be interpreted");
Expand Down

0 comments on commit d5e1943

Please sign in to comment.