diff --git a/rpcs3/Emu/Cell/SPURecompiler.cpp b/rpcs3/Emu/Cell/SPURecompiler.cpp index 1df393e383..c9b7bc9a0c 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.cpp +++ b/rpcs3/Emu/Cell/SPURecompiler.cpp @@ -7960,17 +7960,134 @@ public: void FCEQ(spu_opcode_t op) { if (g_cfg.core.spu_accurate_xfloat) + { set_vr(op.rt, sext(fcmp_ord(get_vr(op.ra) == get_vr(op.rb)))); + return; + } + + const auto [a, b] = get_vrs(op.ra, op.rb); + const value_t ab[2]{a, b}; + + std::bitset<2> safe_float_compare(0); + std::bitset<2> safe_int_compare(0); + + for (u32 i = 0; i < 2; i++) + { + if (auto [ok, data] = get_const_vector(ab[i].value, m_pos, 6000); ok) + { + safe_float_compare.set(i); + safe_int_compare.set(i); + + for (u32 j = 0; j < 4; j++) + { + const u32 value = data._u32[j]; + const u8 exponent = static_cast(value >> 23); + + // unsafe if nan + if (exponent == 255) + { + safe_float_compare.reset(i); + } + + // unsafe if denormal or 0 + if (!exponent) + { + safe_int_compare.reset(i); + } + } + } + } + + if (safe_float_compare.any()) + { + set_vr(op.rt, sext(fcmp_ord(a == b))); + return; + } + + if (safe_int_compare.any()) + { + set_vr(op.rt, sext(bitcast(a) == bitcast(b))); + return; + } + + if (g_cfg.core.spu_approx_xfloat) + { + const auto ai = eval(bitcast(a)); + const auto bi = eval(bitcast(b)); + set_vr(op.rt, sext(fcmp_ord(a == b)) | sext(ai == bi)); + } else - set_vr(op.rt, sext(fcmp_ord(get_vr(op.ra) == get_vr(op.rb)))); + { + set_vr(op.rt, sext(fcmp_ord(a == b))); + } } void FCMEQ(spu_opcode_t op) { if (g_cfg.core.spu_accurate_xfloat) + { set_vr(op.rt, sext(fcmp_ord(fabs(get_vr(op.ra)) == fabs(get_vr(op.rb))))); + return; + } + + const auto [a, b] = get_vrs(op.ra, op.rb); + const value_t ab[2]{a, b}; + + std::bitset<2> safe_float_compare(0); + std::bitset<2> safe_int_compare(0); + + for (u32 i = 0; i < 2; i++) + { + if (auto [ok, data] = get_const_vector(ab[i].value, m_pos, 6000); ok) + { + safe_float_compare.set(i); + safe_int_compare.set(i); + + for (u32 j = 0; j < 4; j++) + { + const u32 value = data._u32[j]; + const u8 exponent = static_cast(value >> 23); + + // unsafe if nan + if (exponent == 255) + { + safe_float_compare.reset(i); + } + + // unsafe if denormal or 0 + if (!exponent) + { + safe_int_compare.reset(i); + } + } + } + } + + const auto fa = eval(fabs(a)); + const auto fb = eval(fabs(b)); + + if (safe_float_compare.any()) + { + set_vr(op.rt, sext(fcmp_ord(fa == fb))); + return; + } + + if (safe_int_compare.any()) + { + set_vr(op.rt, sext(bitcast(fa) == bitcast(fb))); + return; + } + + if (g_cfg.core.spu_approx_xfloat) + { + const auto ai = eval(bitcast(fa)); + const auto bi = eval(bitcast(fb)); + set_vr(op.rt, sext(fcmp_ord(fa == fb)) | sext(ai == bi)); + } else - set_vr(op.rt, sext(fcmp_ord(fabs(get_vr(op.ra)) == fabs(get_vr(op.rb))))); + { + set_vr(op.rt, sext(fcmp_ord(fa == fb))); + } } value_t fma32x4(value_t a, value_t b, value_t c)