JIT: fix fsel/ps_sel implementations for NaN input

fselx was the main problem, but ps_sel was wrong too (even if there were no
known reported bugs with it).

This fixes Beyond Good and Evil (at the least).
This commit is contained in:
Fiora 2014-09-19 01:40:02 -07:00
parent bd740ae9c7
commit c130a496f2
2 changed files with 13 additions and 11 deletions

View File

@ -212,10 +212,12 @@ void Jit64::fselx(UGeckoInstruction inst)
int c = inst.FC;
fpr.Lock(a, b, c, d);
MOVSD(XMM0, fpr.R(a));
PXOR(XMM1, R(XMM1));
// XMM0 = XMM0 < 0 ? all 1s : all 0s
CMPSD(XMM0, R(XMM1), LT);
MOVSD(XMM1, fpr.R(a));
PXOR(XMM0, R(XMM0));
// This condition is very tricky; there's only one right way to handle both the case of
// negative/positive zero and NaN properly.
// (a >= -0.0 ? c : b) transforms into (0 > a ? b : c), hence the NLE.
CMPSD(XMM0, R(XMM1), NLE);
if (cpu_info.bSSE4_1)
{
MOVSD(XMM1, fpr.R(c));
@ -228,7 +230,7 @@ void Jit64::fselx(UGeckoInstruction inst)
PANDN(XMM1, fpr.R(c));
POR(XMM1, R(XMM0));
}
fpr.BindToRegister(d, false);
fpr.BindToRegister(d, true);
MOVSD(fpr.RX(d), R(XMM1));
fpr.UnlockAll();
}

View File

@ -43,17 +43,17 @@ void Jit64::ps_sel(UGeckoInstruction inst)
if (cpu_info.bSSE4_1)
{
MOVAPD(XMM0, fpr.R(a));
PXOR(XMM1, R(XMM1));
CMPPD(XMM0, R(XMM1), LT); // XMM0 = XMM0 < 0 ? all 1s : all 0s
MOVAPD(XMM1, fpr.R(a));
PXOR(XMM0, R(XMM0));
CMPPD(XMM0, R(XMM1), NLE);
MOVAPD(XMM1, fpr.R(c));
BLENDVPD(XMM1, fpr.R(b));
}
else
{
MOVAPD(XMM1, fpr.R(a));
PXOR(XMM0, R(XMM0));
CMPPD(XMM1, R(XMM0), LT); // XMM0 = XMM0 < 0 ? all 1s : all 0s
MOVAPD(XMM0, fpr.R(a));
PXOR(XMM1, R(XMM1));
CMPPD(XMM1, R(XMM0), NLE);
MOVAPD(XMM0, R(XMM1));
PAND(XMM1, fpr.R(b));
PANDN(XMM0, fpr.R(c));