From acfba51b70dc5c0fb8feb604e2c55371e7a096e3 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Wed, 29 May 2024 21:37:58 +0200 Subject: [PATCH] Jit: Fix "skip redundant flushes" for skipped instructions Normally when an instruction is skipped (for instance due to branch merging or BLR optimization), the registers that would have been flushed at the end of that instruction will instead be flushed at the end of the next instruction, which is maybe not perfect, but usually good enough. However, since the addition of the "skip redundant flushes" logic in fd511a689f, Dolphin has accidentally skipped flushing those registers, which creates unnecessary register pressure. This commit restores the old behavior. --- Source/Core/Core/PowerPC/Jit64/Jit.cpp | 18 +++++++++++---- Source/Core/Core/PowerPC/JitArm64/Jit.cpp | 27 +++++++++++++++++------ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp index 1248b1ab01..f31ad18913 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp @@ -992,6 +992,11 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC) IntializeSpeculativeConstants(); } + BitSet32 previous_gpr_in_use{}; + BitSet32 previous_fpr_in_use{}; + BitSet32 previous_gpr_will_be_written{}; + BitSet32 previous_fpr_will_be_written{}; + // Translate instructions for (u32 i = 0; i < code_block.m_num_instructions; i++) { @@ -1233,12 +1238,17 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC) gpr.Discard(op.gprDiscardable); fpr.Discard(op.fprDiscardable); } - gpr.Flush(~(op.gprWillBeRead | op.gprWillBeWritten) & (op.regsIn | op.regsOut), + gpr.Flush(~(op.gprWillBeRead | op.gprWillBeWritten) & previous_gpr_in_use, RegCache::FlushMode::Full); - fpr.Flush(~(op.fprWillBeRead | op.fprWillBeWritten) & (op.fregsIn | op.GetFregsOut()), + fpr.Flush(~(op.fprWillBeRead | op.fprWillBeWritten) & previous_fpr_in_use, RegCache::FlushMode::Full); - gpr.Flush(~op.gprWillBeWritten & op.regsOut, RegCache::FlushMode::Undirty); - fpr.Flush(~op.fprWillBeWritten & op.GetFregsOut(), RegCache::FlushMode::Undirty); + gpr.Flush(~op.gprWillBeWritten & previous_gpr_will_be_written, RegCache::FlushMode::Undirty); + fpr.Flush(~op.fprWillBeWritten & previous_fpr_will_be_written, RegCache::FlushMode::Undirty); + + previous_gpr_in_use = op.gprWillBeRead | op.gprWillBeWritten; + previous_fpr_in_use = op.fprWillBeRead | op.fprWillBeWritten; + previous_gpr_will_be_written = op.gprWillBeWritten; + previous_fpr_will_be_written = op.fprWillBeWritten; if (opinfo->flags & FL_LOADSTORE) ++js.numLoadStoreInst; diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp index aba973346d..4258fb999d 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp @@ -1207,6 +1207,13 @@ bool JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC) IntializeSpeculativeConstants(); } + BitSet32 previous_gpr_in_use{}; + BitSet32 previous_fpr_in_use{}; + BitSet8 previous_cr_in_use{}; + BitSet32 previous_gpr_will_be_written{}; + BitSet32 previous_fpr_will_be_written{}; + BitSet8 previous_cr_will_be_written{}; + // Translate instructions for (u32 i = 0; i < code_block.m_num_instructions; i++) { @@ -1416,16 +1423,22 @@ bool JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC) fpr.DiscardRegisters(op.fprDiscardable); gpr.DiscardCRRegisters(op.crDiscardable); } - gpr.FlushRegisters(~(op.gprWillBeRead | op.gprWillBeWritten) & (op.regsIn | op.regsOut), + gpr.FlushRegisters(~(op.gprWillBeRead | op.gprWillBeWritten) & previous_gpr_in_use, FlushMode::Full); - fpr.FlushRegisters(~(op.fprWillBeRead | op.fprWillBeWritten) & - (op.fregsIn | op.GetFregsOut()), + fpr.FlushRegisters(~(op.fprWillBeRead | op.fprWillBeWritten) & previous_fpr_in_use, FlushMode::Full); - gpr.FlushCRRegisters(~(op.crWillBeRead | op.crWillBeWritten) & (op.crIn | op.crOut), + gpr.FlushCRRegisters(~(op.crWillBeRead | op.crWillBeWritten) & previous_cr_in_use, FlushMode::Full); - gpr.FlushRegisters(~op.gprWillBeWritten & op.regsOut, FlushMode::Undirty); - fpr.FlushRegisters(~op.fprWillBeWritten & op.GetFregsOut(), FlushMode::Undirty); - gpr.FlushCRRegisters(~op.crWillBeWritten & op.crOut, FlushMode::Undirty); + gpr.FlushRegisters(~op.gprWillBeWritten & previous_gpr_will_be_written, FlushMode::Undirty); + fpr.FlushRegisters(~op.fprWillBeWritten & previous_fpr_will_be_written, FlushMode::Undirty); + gpr.FlushCRRegisters(~op.crWillBeWritten & previous_cr_will_be_written, FlushMode::Undirty); + + previous_gpr_in_use = op.gprWillBeRead | op.gprWillBeWritten; + previous_fpr_in_use = op.fprWillBeRead | op.fprWillBeWritten; + previous_cr_in_use = op.crWillBeRead | op.crWillBeWritten; + previous_gpr_will_be_written = op.gprWillBeWritten; + previous_fpr_will_be_written = op.fprWillBeWritten; + previous_cr_will_be_written = op.crWillBeWritten; if (opinfo->flags & FL_LOADSTORE) ++js.numLoadStoreInst;