Fix PPC_FP on non-sse4.1 code paths.
The Invalid bit on the x87 fpu is sticky, so once a single NaN goes through the old code on CPUs without sse4.1 all future floats are mutilated. Patch to emulate PTEST by Fiora. Fixes issue 7237 and issue 7510.
This commit is contained in:
parent
96cfbd1bb0
commit
8c857b45f8
|
@ -551,6 +551,8 @@ void EmuCodeBlock::ForceSinglePrecisionP(X64Reg xmm) {
|
|||
static u32 GC_ALIGNED16(temp32);
|
||||
static u64 GC_ALIGNED16(temp64);
|
||||
|
||||
static const float GC_ALIGNED16(m_zero[]) = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
|
||||
#if _M_X86_64
|
||||
static const __m128i GC_ALIGNED16(single_qnan_bit) = _mm_set_epi64x(0, 0x0000000000400000);
|
||||
static const __m128i GC_ALIGNED16(single_exponent) = _mm_set_epi64x(0, 0x000000007f800000);
|
||||
|
@ -669,8 +671,13 @@ void EmuCodeBlock::ConvertDoubleToSingle(X64Reg dst, X64Reg src)
|
|||
PTEST(XMM1, M((void *)&double_exponent));
|
||||
cond = CC_NC;
|
||||
} else {
|
||||
FNSTSW_AX();
|
||||
TEST(16, R(AX), Imm16(x87_InvalidOperation));
|
||||
// emulate PTEST; checking FPU flags is incorrect because the NaN bits
|
||||
// are sticky (persist between instructions)
|
||||
MOVSD(XMM0, M((void *)&double_exponent));
|
||||
PAND(XMM0, R(XMM1));
|
||||
PCMPEQB(XMM0, M((void *)&m_zero));
|
||||
PMOVMSKB(EAX, R(XMM0));
|
||||
CMP(32, R(EAX), Imm32(0xffff));
|
||||
cond = CC_Z;
|
||||
}
|
||||
FSTP(32, M(&temp32));
|
||||
|
@ -706,8 +713,13 @@ void EmuCodeBlock::ConvertSingleToDouble(X64Reg dst, X64Reg src, bool src_is_gpr
|
|||
PTEST(XMM1, M((void *)&single_exponent));
|
||||
cond = CC_NC;
|
||||
} else {
|
||||
FNSTSW_AX();
|
||||
TEST(16, R(AX), Imm16(x87_InvalidOperation));
|
||||
// emulate PTEST; checking FPU flags is incorrect because the NaN bits
|
||||
// are sticky (persist between instructions)
|
||||
MOVSS(XMM0, M((void *)&single_exponent));
|
||||
PAND(XMM0, R(XMM1));
|
||||
PCMPEQB(XMM0, M((void *)&m_zero));
|
||||
PMOVMSKB(EAX, R(XMM0));
|
||||
CMP(32, R(EAX), Imm32(0xffff));
|
||||
cond = CC_Z;
|
||||
}
|
||||
FSTP(64, M(&temp64));
|
||||
|
|
|
@ -57,8 +57,9 @@ public:
|
|||
void ForceSinglePrecisionS(Gen::X64Reg xmm);
|
||||
void ForceSinglePrecisionP(Gen::X64Reg xmm);
|
||||
|
||||
// AX might get trashed
|
||||
// EAX might get trashed
|
||||
void ConvertSingleToDouble(Gen::X64Reg dst, Gen::X64Reg src, bool src_is_gpr = false);
|
||||
// EAX might get trashed
|
||||
void ConvertDoubleToSingle(Gen::X64Reg dst, Gen::X64Reg src);
|
||||
protected:
|
||||
std::unordered_map<u8 *, u32> registersInUseAtLoc;
|
||||
|
|
Loading…
Reference in New Issue