PPU LLVM: Accelerate NJ handling in FTZ environment

This commit is contained in:
Elad
2026-07-16 16:17:27 +03:00
parent 656bc2a92c
commit e9f833a2e8
10 changed files with 27 additions and 43 deletions
+1 -1
View File
@@ -7354,7 +7354,7 @@ ppu_interpreter_rt_base::ppu_interpreter_rt_base() noexcept
selected += set_sat; selected += set_sat;
if (g_cfg.core.ppu_use_nj_bit) if (g_cfg.core.ppu_use_nj_bit)
selected += use_nj + fix_nj; selected += use_nj + fix_nj;
if (g_cfg.core.ppu_llvm_nj_fixup) if (!g_cfg.core.set_daz_and_ftz)
selected += fix_nj; selected += fix_nj;
if (g_cfg.core.ppu_set_vnan) if (g_cfg.core.ppu_set_vnan)
selected += set_vnan + fix_vnan; selected += set_vnan + fix_vnan;
+3 -4
View File
@@ -5144,7 +5144,7 @@ bool ppu_initialize(const ppu_module<lv2_obj>& info, bool check_only, u64 file_s
platform_bit, platform_bit,
accurate_dfma, accurate_dfma,
fixup_vnan, fixup_vnan,
fixup_nj_denormals, _reserved_for_backwards_compatibility,
accurate_cache_line_stores, accurate_cache_line_stores,
reservations_128_byte, reservations_128_byte,
greedy_mode, greedy_mode,
@@ -5160,6 +5160,7 @@ bool ppu_initialize(const ppu_module<lv2_obj>& info, bool check_only, u64 file_s
be_t<bs_t<ppu_settings>> settings{}; be_t<bs_t<ppu_settings>> settings{};
settings += ppu_settings::_reserved_for_backwards_compatibility;
#if !defined(_WIN32) && !defined(__APPLE__) #if !defined(_WIN32) && !defined(__APPLE__)
settings += ppu_settings::platform_bit; settings += ppu_settings::platform_bit;
#endif #endif
@@ -5167,8 +5168,6 @@ bool ppu_initialize(const ppu_module<lv2_obj>& info, bool check_only, u64 file_s
settings += ppu_settings::accurate_dfma; settings += ppu_settings::accurate_dfma;
if (g_cfg.core.ppu_fix_vnan) if (g_cfg.core.ppu_fix_vnan)
settings += ppu_settings::fixup_vnan; settings += ppu_settings::fixup_vnan;
if (g_cfg.core.ppu_llvm_nj_fixup)
settings += ppu_settings::fixup_nj_denormals;
if (has_dcbz == 2) if (has_dcbz == 2)
settings += ppu_settings::accurate_cache_line_stores; settings += ppu_settings::accurate_cache_line_stores;
if (g_cfg.core.ppu_128_reservations_loop_max_length) if (g_cfg.core.ppu_128_reservations_loop_max_length)
@@ -5182,7 +5181,7 @@ bool ppu_initialize(const ppu_module<lv2_obj>& info, bool check_only, u64 file_s
if (g_cfg.core.ppu_set_vnan) if (g_cfg.core.ppu_set_vnan)
settings += ppu_settings::accurate_vnan, settings -= ppu_settings::fixup_vnan, fmt::throw_exception("VNAN Not implemented"); settings += ppu_settings::accurate_vnan, settings -= ppu_settings::fixup_vnan, fmt::throw_exception("VNAN Not implemented");
if (g_cfg.core.ppu_use_nj_bit) 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) 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 settings += ppu_settings::contains_symbol_resolver; // Avoid invalidating all modules for this purpose
if (g_cfg.core.set_daz_and_ftz) if (g_cfg.core.set_daz_and_ftz)
+9 -10
View File
@@ -482,10 +482,10 @@ Value* PPUTranslator::VecHandleDenormal(Value* val)
return bitcast(result, type); 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_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; 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 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<bool>()); const auto nj = Trunc(m_ir->CreateLShr(vscr, 16), GetType<bool>());
RegStore(nj, m_nj); 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) if (g_cfg.core.ppu_set_sat_bit)
RegStore(m_ir->CreateInsertElement(ConstantAggregateZero::get(GetType<u32[4]>()), m_ir->CreateAnd(vscr, 1), m_ir->getInt32(0)), m_sat); RegStore(m_ir->CreateInsertElement(ConstantAggregateZero::get(GetType<u32[4]>()), 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) void PPUTranslator::VEXPTEFP(ppu_opcode_t op)
{ {
const auto b = get_vr<f32[4]>(op.vb); const auto b = get_vr<f32[4]>(op.vb);
set_vr(op.vd, vec_handle_result(llvm_calli<f32[4], decltype(b)>{"llvm.exp2.v4f32", {b}})); set_vr(op.vd, vec_handle_result(llvm_calli<f32[4], decltype(b)>{"llvm.exp2.v4f32", {b}}, true));
} }
void PPUTranslator::VLOGEFP(ppu_opcode_t op) void PPUTranslator::VLOGEFP(ppu_opcode_t op)
{ {
const auto b = get_vr<f32[4]>(op.vb); const auto b = get_vr<f32[4]>(op.vb);
set_vr(op.vd, vec_handle_result(llvm_calli<f32[4], decltype(b)>{"llvm.log2.v4f32", {b}})); set_vr(op.vd, vec_handle_result(llvm_calli<f32[4], decltype(b)>{"llvm.log2.v4f32", {b}}, true));
} }
void PPUTranslator::VMADDFP(ppu_opcode_t op) void PPUTranslator::VMADDFP(ppu_opcode_t op)
@@ -1345,9 +1344,9 @@ void PPUTranslator::VMAXFP(ppu_opcode_t op)
{ {
const auto [a, b] = get_vrs<f32[4]>(op.va, op.vb); const auto [a, b] = get_vrs<f32[4]>(op.va, op.vb);
#ifdef ARCH_ARM64 #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 #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 #endif
} }
@@ -1411,9 +1410,9 @@ void PPUTranslator::VMINFP(ppu_opcode_t op)
{ {
const auto [a, b] = get_vrs<f32[4]>(op.va, op.vb); const auto [a, b] = get_vrs<f32[4]>(op.va, op.vb);
#ifdef ARCH_ARM64 #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 #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 #endif
} }
+3 -3
View File
@@ -116,13 +116,13 @@ public:
llvm::Value* VecHandleNan(llvm::Value* val); llvm::Value* VecHandleNan(llvm::Value* val);
llvm::Value* VecHandleDenormal(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 <typename T> template <typename T>
auto vec_handle_result(T&& expr) auto vec_handle_result(T&& expr, bool flush_denormals_manually = false)
{ {
value_t<typename T::type> result; value_t<typename T::type> result;
result.value = VecHandleResult(expr.eval(m_ir)); result.value = VecHandleResult(expr.eval(m_ir), flush_denormals_manually);
return result; return result;
} }
-1
View File
@@ -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<-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::_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 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 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 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. cfg::_bool ppu_set_sat_bit{ this, "PPU Set Saturation Bit", false }; // Accuracy. If unset, completely disable saturation flag handling.
-1
View File
@@ -47,7 +47,6 @@ const std::map<emu_settings_type, cfg_location> settings_location =
{ emu_settings_type::AccuratePPU128Loop, get_cfg_location(local_cfg.core.ppu_128_reservations_loop_max_length) }, { 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::PerformanceReport, get_cfg_location(local_cfg.core.perf_report) },
{ emu_settings_type::NumPPUThreads, get_cfg_location(local_cfg.core.ppu_threads) }, { 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::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::AccurateDFMA, get_cfg_location(local_cfg.core.use_accurate_dfma) },
{ emu_settings_type::AccuratePPUSAT, get_cfg_location(local_cfg.core.ppu_set_sat_bit) }, { emu_settings_type::AccuratePPUSAT, get_cfg_location(local_cfg.core.ppu_set_sat_bit) },
-1
View File
@@ -41,7 +41,6 @@ enum class emu_settings_type
SleepTimersAccuracy, SleepTimersAccuracy,
ClocksScale, ClocksScale,
PerformanceReport, PerformanceReport,
PPUNJFixup,
PPUVNANFixup, PPUVNANFixup,
AccurateDFMA, AccurateDFMA,
AccuratePPUSAT, AccuratePPUSAT,
+3 -6
View File
@@ -1525,9 +1525,6 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> gui_settings, std
m_emu_settings->EnhanceCheckBox(ui->accurateSpuDMA, emu_settings_type::AccurateSpuDMA); m_emu_settings->EnhanceCheckBox(ui->accurateSpuDMA, emu_settings_type::AccurateSpuDMA);
SubscribeTooltip(ui->accurateSpuDMA, tooltips.settings.accurate_spu_dma); 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); m_emu_settings->EnhanceCheckBox(ui->PPUVNANfixup, emu_settings_type::PPUVNANFixup);
SubscribeTooltip(ui->PPUVNANfixup, tooltips.settings.fixup_ppuvnan); SubscribeTooltip(ui->PPUVNANfixup, tooltips.settings.fixup_ppuvnan);
@@ -1558,6 +1555,9 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> gui_settings, std
m_emu_settings->EnhanceCheckBox(ui->handleTiledMemory, emu_settings_type::HandleRSXTiledMemory); m_emu_settings->EnhanceCheckBox(ui->handleTiledMemory, emu_settings_type::HandleRSXTiledMemory);
SubscribeTooltip(ui->handleTiledMemory, tooltips.settings.handle_tiled_memory); 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); m_emu_settings->EnhanceCheckBox(ui->vblankNTSCFixup, emu_settings_type::VBlankNTSCFixup);
ui->mfcDelayCommand->setChecked(m_emu_settings->GetSetting(emu_settings_type::MFCCommandsShuffling) == "1"); 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> gui_settings, std
m_emu_settings->EnhanceCheckBox(ui->mfcDebug, emu_settings_type::MFCDebug); m_emu_settings->EnhanceCheckBox(ui->mfcDebug, emu_settings_type::MFCDebug);
SubscribeTooltip(ui->mfcDebug, tooltips.settings.mfc_debug); 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); m_emu_settings->EnhanceCheckBox(ui->accuratePPUSAT, emu_settings_type::AccuratePPUSAT);
SubscribeTooltip(ui->accuratePPUSAT, tooltips.settings.accurate_ppusat); SubscribeTooltip(ui->accuratePPUSAT, tooltips.settings.accurate_ppusat);
+7 -14
View File
@@ -2491,6 +2491,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="setDAZandFTZ">
<property name="text">
<string>PPU Set DAZ and FTZ</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QCheckBox" name="mfcDelayCommand"> <widget class="QCheckBox" name="mfcDelayCommand">
<property name="text"> <property name="text">
@@ -4526,13 +4533,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="setDAZandFTZ">
<property name="text">
<string>PPU Set DAZ and FTZ</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QCheckBox" name="spuDebug"> <widget class="QCheckBox" name="spuDebug">
<property name="text"> <property name="text">
@@ -4611,13 +4611,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="ppuNJFixup">
<property name="text">
<string>Approximate PPU Non-Java Mode</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QCheckBox" name="PPUVNANfixup"> <widget class="QCheckBox" name="PPUVNANfixup">
<property name="text"> <property name="text">
+1 -2
View File
@@ -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_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_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 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 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 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."); 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 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 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 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_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_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."); const QString accurate_ppuvnan = tr("Accurately set NaN results in vector instructions in PPU backends.\nIf unsure, do not modify this setting.");