From e9f833a2e8ad0d02652c18f69232ccdde5c5999f Mon Sep 17 00:00:00 2001 From: Elad <18193363+elad335@users.noreply.github.com> Date: Thu, 16 Jul 2026 16:17:27 +0300 Subject: [PATCH] PPU LLVM: Accelerate NJ handling in FTZ environment --- rpcs3/Emu/Cell/PPUInterpreter.cpp | 2 +- rpcs3/Emu/Cell/PPUThread.cpp | 7 +++---- rpcs3/Emu/Cell/PPUTranslator.cpp | 19 +++++++++---------- rpcs3/Emu/Cell/PPUTranslator.h | 6 +++--- rpcs3/Emu/system_config.h | 1 - rpcs3/rpcs3qt/emu_settings_type.cpp | 1 - rpcs3/rpcs3qt/emu_settings_type.h | 1 - rpcs3/rpcs3qt/settings_dialog.cpp | 9 +++------ rpcs3/rpcs3qt/settings_dialog.ui | 21 +++++++-------------- rpcs3/rpcs3qt/tooltips.h | 3 +-- 10 files changed, 27 insertions(+), 43 deletions(-) diff --git a/rpcs3/Emu/Cell/PPUInterpreter.cpp b/rpcs3/Emu/Cell/PPUInterpreter.cpp index 3fa6d09f7b..d01eac389b 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.cpp +++ b/rpcs3/Emu/Cell/PPUInterpreter.cpp @@ -7354,7 +7354,7 @@ ppu_interpreter_rt_base::ppu_interpreter_rt_base() noexcept selected += set_sat; if (g_cfg.core.ppu_use_nj_bit) selected += use_nj + fix_nj; - if (g_cfg.core.ppu_llvm_nj_fixup) + if (!g_cfg.core.set_daz_and_ftz) selected += fix_nj; if (g_cfg.core.ppu_set_vnan) selected += set_vnan + fix_vnan; diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 005e3be9e6..c5ec1e929d 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -5144,7 +5144,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_s platform_bit, accurate_dfma, fixup_vnan, - fixup_nj_denormals, + _reserved_for_backwards_compatibility, accurate_cache_line_stores, reservations_128_byte, greedy_mode, @@ -5160,6 +5160,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_s be_t> settings{}; + settings += ppu_settings::_reserved_for_backwards_compatibility; #if !defined(_WIN32) && !defined(__APPLE__) settings += ppu_settings::platform_bit; #endif @@ -5167,8 +5168,6 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_s settings += ppu_settings::accurate_dfma; if (g_cfg.core.ppu_fix_vnan) settings += ppu_settings::fixup_vnan; - if (g_cfg.core.ppu_llvm_nj_fixup) - settings += ppu_settings::fixup_nj_denormals; if (has_dcbz == 2) settings += ppu_settings::accurate_cache_line_stores; if (g_cfg.core.ppu_128_reservations_loop_max_length) @@ -5182,7 +5181,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_s if (g_cfg.core.ppu_set_vnan) settings += ppu_settings::accurate_vnan, settings -= ppu_settings::fixup_vnan, fmt::throw_exception("VNAN Not implemented"); if (g_cfg.core.ppu_use_nj_bit) - settings += ppu_settings::accurate_nj_mode, settings -= ppu_settings::fixup_nj_denormals, fmt::throw_exception("NJ Not implemented"); + settings += ppu_settings::accurate_nj_mode, fmt::throw_exception("NJ Not implemented"); if (fpos >= info.get_funcs().size() || module_counter % c_moudles_per_jit == c_moudles_per_jit - 1) settings += ppu_settings::contains_symbol_resolver; // Avoid invalidating all modules for this purpose if (g_cfg.core.set_daz_and_ftz) diff --git a/rpcs3/Emu/Cell/PPUTranslator.cpp b/rpcs3/Emu/Cell/PPUTranslator.cpp index f39ae4394f..8d384300f0 100644 --- a/rpcs3/Emu/Cell/PPUTranslator.cpp +++ b/rpcs3/Emu/Cell/PPUTranslator.cpp @@ -482,10 +482,10 @@ Value* PPUTranslator::VecHandleDenormal(Value* val) return bitcast(result, type); } -Value* PPUTranslator::VecHandleResult(Value* val) +Value* PPUTranslator::VecHandleResult(Value* val, bool flush_denormals_manually) { val = g_cfg.core.ppu_fix_vnan ? VecHandleNan(val) : val; - val = g_cfg.core.ppu_llvm_nj_fixup ? VecHandleDenormal(val) : val; + val = flush_denormals_manually || !g_cfg.core.set_daz_and_ftz ? VecHandleDenormal(val) : val; return val; } @@ -995,8 +995,7 @@ void PPUTranslator::MTVSCR(ppu_opcode_t op) const auto vscr = m_ir->CreateExtractElement(GetVr(op.vb, VrType::vi32), m_ir->getInt32(m_is_be ? 3 : 0)); const auto nj = Trunc(m_ir->CreateLShr(vscr, 16), GetType()); RegStore(nj, m_nj); - if (g_cfg.core.ppu_llvm_nj_fixup) - RegStore(m_ir->CreateSelect(nj, m_ir->getInt32(0x7f80'0000), m_ir->getInt32(0x7fff'ffff)), m_jm_mask); + RegStore(m_ir->CreateSelect(nj, m_ir->getInt32(0x7f80'0000), m_ir->getInt32(0x7fff'ffff)), m_jm_mask); if (g_cfg.core.ppu_set_sat_bit) RegStore(m_ir->CreateInsertElement(ConstantAggregateZero::get(GetType()), m_ir->CreateAnd(vscr, 1), m_ir->getInt32(0)), m_sat); } @@ -1295,13 +1294,13 @@ void PPUTranslator::VCTUXS(ppu_opcode_t op) void PPUTranslator::VEXPTEFP(ppu_opcode_t op) { const auto b = get_vr(op.vb); - set_vr(op.vd, vec_handle_result(llvm_calli{"llvm.exp2.v4f32", {b}})); + set_vr(op.vd, vec_handle_result(llvm_calli{"llvm.exp2.v4f32", {b}}, true)); } void PPUTranslator::VLOGEFP(ppu_opcode_t op) { const auto b = get_vr(op.vb); - set_vr(op.vd, vec_handle_result(llvm_calli{"llvm.log2.v4f32", {b}})); + set_vr(op.vd, vec_handle_result(llvm_calli{"llvm.log2.v4f32", {b}}, true)); } void PPUTranslator::VMADDFP(ppu_opcode_t op) @@ -1345,9 +1344,9 @@ void PPUTranslator::VMAXFP(ppu_opcode_t op) { const auto [a, b] = get_vrs(op.va, op.vb); #ifdef ARCH_ARM64 - set_vr(op.vd, vec_handle_result(fmax(a, b))); + set_vr(op.vd, vec_handle_result(fmax(a, b), true)); #else - set_vr(op.vd, vec_handle_result(select(fcmp_ord(a < b) | fcmp_uno(b != b), b, a))); + set_vr(op.vd, vec_handle_result(select(fcmp_ord(a < b) | fcmp_uno(b != b), b, a), true)); #endif } @@ -1411,9 +1410,9 @@ void PPUTranslator::VMINFP(ppu_opcode_t op) { const auto [a, b] = get_vrs(op.va, op.vb); #ifdef ARCH_ARM64 - set_vr(op.vd, vec_handle_result(fmin(a, b))); + set_vr(op.vd, vec_handle_result(fmin(a, b), true)); #else - set_vr(op.vd, vec_handle_result(select(fcmp_ord(a > b) | fcmp_uno(b != b), b, a))); + set_vr(op.vd, vec_handle_result(select(fcmp_ord(a > b) | fcmp_uno(b != b), b, a), true)); #endif } diff --git a/rpcs3/Emu/Cell/PPUTranslator.h b/rpcs3/Emu/Cell/PPUTranslator.h index be84d8061e..1d99b27f8e 100644 --- a/rpcs3/Emu/Cell/PPUTranslator.h +++ b/rpcs3/Emu/Cell/PPUTranslator.h @@ -116,13 +116,13 @@ public: llvm::Value* VecHandleNan(llvm::Value* val); llvm::Value* VecHandleDenormal(llvm::Value* val); - llvm::Value* VecHandleResult(llvm::Value* val); + llvm::Value* VecHandleResult(llvm::Value* val, bool flush_denormals_manually = false); template - auto vec_handle_result(T&& expr) + auto vec_handle_result(T&& expr, bool flush_denormals_manually = false) { value_t result; - result.value = VecHandleResult(expr.eval(m_ir)); + result.value = VecHandleResult(expr.eval(m_ir), flush_denormals_manually); return result; } diff --git a/rpcs3/Emu/system_config.h b/rpcs3/Emu/system_config.h index c431ee2f5a..e1170c0833 100644 --- a/rpcs3/Emu/system_config.h +++ b/rpcs3/Emu/system_config.h @@ -66,7 +66,6 @@ struct cfg_root : cfg::node cfg::_int<-1, 14> ppu_128_reservations_loop_max_length{ this, "Accurate PPU 128-byte Reservation Op Max Length", 0, true }; // -1: Always accurate, 0: Never accurate, 1-14: max accurate loop length cfg::_int<-64, 64> stub_ppu_traps{ this, "Stub PPU Traps", 0, true }; // Hack, skip PPU traps for rare cases where the trap is continueable (specify relative instructions to skip) cfg::_bool precise_spu_verification{ this, "Precise SPU Verification", false }; // Disables use of xorsum based spu verification if enabled. - cfg::_bool ppu_llvm_nj_fixup{ this, "PPU LLVM Java Mode Handling", true }; // Partially respect current Java Mode for alti-vec ops by PPU LLVM cfg::_bool ppu_fix_vnan{ this, "PPU Vector NaN Handling", true }; // Accuracy. Partial. cfg::_bool use_accurate_dfma{ this, "Use Accurate DFMA", true }; // Enable accurate double-precision FMA for CPUs which do not support it natively cfg::_bool ppu_set_sat_bit{ this, "PPU Set Saturation Bit", false }; // Accuracy. If unset, completely disable saturation flag handling. diff --git a/rpcs3/rpcs3qt/emu_settings_type.cpp b/rpcs3/rpcs3qt/emu_settings_type.cpp index e8de70f334..dc1e0c2ada 100644 --- a/rpcs3/rpcs3qt/emu_settings_type.cpp +++ b/rpcs3/rpcs3qt/emu_settings_type.cpp @@ -47,7 +47,6 @@ const std::map settings_location = { emu_settings_type::AccuratePPU128Loop, get_cfg_location(local_cfg.core.ppu_128_reservations_loop_max_length) }, { emu_settings_type::PerformanceReport, get_cfg_location(local_cfg.core.perf_report) }, { emu_settings_type::NumPPUThreads, get_cfg_location(local_cfg.core.ppu_threads) }, - { emu_settings_type::PPUNJFixup, get_cfg_location(local_cfg.core.ppu_llvm_nj_fixup) }, { emu_settings_type::PPUVNANFixup, get_cfg_location(local_cfg.core.ppu_fix_vnan) }, { emu_settings_type::AccurateDFMA, get_cfg_location(local_cfg.core.use_accurate_dfma) }, { emu_settings_type::AccuratePPUSAT, get_cfg_location(local_cfg.core.ppu_set_sat_bit) }, diff --git a/rpcs3/rpcs3qt/emu_settings_type.h b/rpcs3/rpcs3qt/emu_settings_type.h index 0f3cd313a9..53c4badc71 100644 --- a/rpcs3/rpcs3qt/emu_settings_type.h +++ b/rpcs3/rpcs3qt/emu_settings_type.h @@ -41,7 +41,6 @@ enum class emu_settings_type SleepTimersAccuracy, ClocksScale, PerformanceReport, - PPUNJFixup, PPUVNANFixup, AccurateDFMA, AccuratePPUSAT, diff --git a/rpcs3/rpcs3qt/settings_dialog.cpp b/rpcs3/rpcs3qt/settings_dialog.cpp index 9bdae9511c..3c779c23eb 100644 --- a/rpcs3/rpcs3qt/settings_dialog.cpp +++ b/rpcs3/rpcs3qt/settings_dialog.cpp @@ -1525,9 +1525,6 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std m_emu_settings->EnhanceCheckBox(ui->accurateSpuDMA, emu_settings_type::AccurateSpuDMA); SubscribeTooltip(ui->accurateSpuDMA, tooltips.settings.accurate_spu_dma); - m_emu_settings->EnhanceCheckBox(ui->ppuNJFixup, emu_settings_type::PPUNJFixup); - SubscribeTooltip(ui->ppuNJFixup, tooltips.settings.fixup_ppunj); - m_emu_settings->EnhanceCheckBox(ui->PPUVNANfixup, emu_settings_type::PPUVNANFixup); SubscribeTooltip(ui->PPUVNANfixup, tooltips.settings.fixup_ppuvnan); @@ -1558,6 +1555,9 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std m_emu_settings->EnhanceCheckBox(ui->handleTiledMemory, emu_settings_type::HandleRSXTiledMemory); SubscribeTooltip(ui->handleTiledMemory, tooltips.settings.handle_tiled_memory); + m_emu_settings->EnhanceCheckBox(ui->setDAZandFTZ, emu_settings_type::SetDAZandFTZ); + SubscribeTooltip(ui->setDAZandFTZ, tooltips.settings.set_daz_and_ftz); + m_emu_settings->EnhanceCheckBox(ui->vblankNTSCFixup, emu_settings_type::VBlankNTSCFixup); ui->mfcDelayCommand->setChecked(m_emu_settings->GetSetting(emu_settings_type::MFCCommandsShuffling) == "1"); @@ -2497,9 +2497,6 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std m_emu_settings->EnhanceCheckBox(ui->mfcDebug, emu_settings_type::MFCDebug); SubscribeTooltip(ui->mfcDebug, tooltips.settings.mfc_debug); - m_emu_settings->EnhanceCheckBox(ui->setDAZandFTZ, emu_settings_type::SetDAZandFTZ); - SubscribeTooltip(ui->setDAZandFTZ, tooltips.settings.set_daz_and_ftz); - m_emu_settings->EnhanceCheckBox(ui->accuratePPUSAT, emu_settings_type::AccuratePPUSAT); SubscribeTooltip(ui->accuratePPUSAT, tooltips.settings.accurate_ppusat); diff --git a/rpcs3/rpcs3qt/settings_dialog.ui b/rpcs3/rpcs3qt/settings_dialog.ui index 6f587470ff..19e0191f2b 100644 --- a/rpcs3/rpcs3qt/settings_dialog.ui +++ b/rpcs3/rpcs3qt/settings_dialog.ui @@ -2491,6 +2491,13 @@ + + + + PPU Set DAZ and FTZ + + + @@ -4526,13 +4533,6 @@ - - - - PPU Set DAZ and FTZ - - - @@ -4611,13 +4611,6 @@ - - - - Approximate PPU Non-Java Mode - - - diff --git a/rpcs3/rpcs3qt/tooltips.h b/rpcs3/rpcs3qt/tooltips.h index 4bc688db38..0d3fba35c1 100644 --- a/rpcs3/rpcs3qt/tooltips.h +++ b/rpcs3/rpcs3qt/tooltips.h @@ -29,7 +29,6 @@ public: const QString accurate_rsx_access = tr("Forces RSX pauses on SPU MFC_GETLLAR and SPU MFC_PUTLLUC operations."); const QString accurate_spu_dma = tr("Accurately processes SPU DMA operations."); const QString accurate_dfma = tr("Use accurate double-precision FMA instructions in PPU and SPU backends.\nWhile disabling it might give a decent performance boost if your CPU doesn't support FMA, it may also introduce subtle bugs that otherwise do not occur.\nYou shouldn't disable it if your CPU supports FMA."); - const QString fixup_ppunj = tr("Legacy option. Fixup result vector values in Non-Java Mode in PPU LLVM.\nIf unsure, do not modify this setting."); const QString fixup_ppuvnan = tr("Fixup NaN results in vector instructions in PPU backends.\nIf unsure, do not modify this setting."); const QString silence_all_logs = tr("Stop writing any logs after game startup. Don't use unless you believe it's necessary."); const QString read_color = tr("Initializes render target memory using vm memory."); @@ -104,7 +103,7 @@ public: const QString ppu_debug = tr("Creates PPU logs.\nOnly useful to developers.\nNever use this."); const QString spu_debug = tr("Creates SPU logs.\nOnly useful to developers.\nNever use this."); const QString mfc_debug = tr("Creates MFC logs.\nOnly useful to developers.\nNever use this."); - const QString set_daz_and_ftz = tr("Sets special MXCSR flags to debug errors in SSE operations.\nOnly used in PPU thread when it's not precise.\nOnly useful to developers.\nNever use this."); + const QString set_daz_and_ftz = tr("Sets special MXCSR flags to debug errors in SSE operations.\nAccelerates PPU performance at the cost of accuracy."); const QString accurate_ppusat = tr("Accurately set Saturation Bit values in PPU backends.\nIf unsure, do not modify this setting."); const QString accurate_ppunj = tr("Respect Non-Java Mode Bit values for vector ops in PPU backends.\nIf unsure, do not modify this setting."); const QString accurate_ppuvnan = tr("Accurately set NaN results in vector instructions in PPU backends.\nIf unsure, do not modify this setting.");