diff --git a/rpcs3/Emu/Cell/SPURecompiler.cpp b/rpcs3/Emu/Cell/SPURecompiler.cpp index af9042e2fa..cd364f3584 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.cpp +++ b/rpcs3/Emu/Cell/SPURecompiler.cpp @@ -7281,6 +7281,22 @@ public: return eval(fmuladd(ca, cb, c)); } + // Checks for postive and negative zero, or Denormal (treated as zero) + bool is_spu_float_zero(v128 a) + { + for (u32 i = 0; i < 4; i++) + { + const u32 exponent = a._u32[i] & 0x7f800000u; + + if (exponent) + { + // Normalized number + return false; + } + } + return true; + } + void FREST(spu_opcode_t op) { // TODO @@ -7317,6 +7333,55 @@ public: const auto a = get_vr(op.ra); const auto b = get_vr(op.rb); + if (auto cv = llvm::dyn_cast(b.value)) + { + v128 data = get_const_vector(cv, m_pos, 5000); + bool safe_int_compare = true; + + for (u32 i = 0; i < 4; i++) + { + const u32 exponent = data._u32[i] & 0x7f800000u; + + if (data._u32[i] > 0x7f7fffffu || !exponent) + { + // Postive or negative zero, Denormal (treated as zero), Negative constant, or Normalized number with exponent +127 + // Cannot used signed integer compare safely + safe_int_compare = false; + break; + } + } + + if (safe_int_compare) + { + set_vr(op.rt, sext(bitcast(a) > bitcast(b))); + return; + } + } + + if (auto cv = llvm::dyn_cast(a.value)) + { + v128 data = get_const_vector(cv, m_pos, 5000); + bool safe_int_compare = true; + + for (u32 i = 0; i < 4; i++) + { + const u32 exponent = data._u32[i] & 0x7f800000u; + + if (data._u32[i] > 0x7f7fffffu || !exponent) + { + // See above + safe_int_compare = false; + break; + } + } + + if (safe_int_compare) + { + set_vr(op.rt, sext(bitcast(a) > bitcast(b))); + return; + } + } + if (g_cfg.core.spu_approx_xfloat) { const auto ca = eval(clamp_positive_smax(a)); @@ -7460,7 +7525,7 @@ public: { v128 data = get_const_vector(cv, m_pos, 4000); - if (data == v128{}) + if (is_spu_float_zero(data)) { r = eval(ca * cb); return r;