diff --git a/src/core/cpu_recompiler_code_generator_aarch64.cpp b/src/core/cpu_recompiler_code_generator_aarch64.cpp index 9d3a6ec14..de2f8ec3c 100644 --- a/src/core/cpu_recompiler_code_generator_aarch64.cpp +++ b/src/core/cpu_recompiler_code_generator_aarch64.cpp @@ -1288,6 +1288,7 @@ Value CodeGenerator::EmitLoadGuestMemory(const CodeBlockInstruction& cbi, const { // We need to use the full 64 bits here since we test the sign bit result. Value result = m_register_cache.AllocateScratch(RegSize_64); + m_register_cache.FlushCallerSavedGuestRegisters(true, true); // NOTE: This can leave junk in the upper bits switch (size) @@ -1357,6 +1358,8 @@ Value CodeGenerator::EmitLoadGuestMemory(const CodeBlockInstruction& cbi, const else { Value result = m_register_cache.AllocateScratch(RegSize_32); + m_register_cache.FlushCallerSavedGuestRegisters(true, true); + switch (size) { case RegSize_8: @@ -1406,6 +1409,8 @@ void CodeGenerator::EmitStoreGuestMemory(const CodeBlockInstruction& cbi, const if (g_settings.cpu_recompiler_memory_exceptions) { Value result = m_register_cache.AllocateScratch(RegSize_32); + m_register_cache.FlushCallerSavedGuestRegisters(true, true); + switch (value.size) { case RegSize_8: @@ -1449,6 +1454,8 @@ void CodeGenerator::EmitStoreGuestMemory(const CodeBlockInstruction& cbi, const } else { + m_register_cache.FlushCallerSavedGuestRegisters(true, true); + switch (value.size) { case RegSize_8: diff --git a/src/core/cpu_recompiler_code_generator_x64.cpp b/src/core/cpu_recompiler_code_generator_x64.cpp index bc41b71cf..e6f85e3e6 100644 --- a/src/core/cpu_recompiler_code_generator_x64.cpp +++ b/src/core/cpu_recompiler_code_generator_x64.cpp @@ -1744,6 +1744,7 @@ Value CodeGenerator::EmitLoadGuestMemory(const CodeBlockInstruction& cbi, const { // We need to use the full 64 bits here since we test the sign bit result. Value result = m_register_cache.AllocateScratch(RegSize_64); + m_register_cache.FlushCallerSavedGuestRegisters(true, true); // NOTE: This can leave junk in the upper bits switch (size) @@ -1811,6 +1812,8 @@ Value CodeGenerator::EmitLoadGuestMemory(const CodeBlockInstruction& cbi, const else { Value result = m_register_cache.AllocateScratch(RegSize_32); + m_register_cache.FlushCallerSavedGuestRegisters(true, true); + switch (size) { case RegSize_8: @@ -1860,6 +1863,8 @@ void CodeGenerator::EmitStoreGuestMemory(const CodeBlockInstruction& cbi, const if (g_settings.cpu_recompiler_memory_exceptions) { Value result = m_register_cache.AllocateScratch(RegSize_32); + m_register_cache.FlushCallerSavedGuestRegisters(true, true); + switch (value.size) { case RegSize_8: @@ -1901,6 +1906,8 @@ void CodeGenerator::EmitStoreGuestMemory(const CodeBlockInstruction& cbi, const } else { + m_register_cache.FlushCallerSavedGuestRegisters(true, true); + switch (value.size) { case RegSize_8: diff --git a/src/core/cpu_recompiler_register_cache.cpp b/src/core/cpu_recompiler_register_cache.cpp index 816e2e89e..dac853c81 100644 --- a/src/core/cpu_recompiler_register_cache.cpp +++ b/src/core/cpu_recompiler_register_cache.cpp @@ -739,6 +739,21 @@ void RegisterCache::FlushAllGuestRegisters(bool invalidate, bool clear_dirty) FlushGuestRegister(static_cast<Reg>(reg), invalidate, clear_dirty); } +void RegisterCache::FlushCallerSavedGuestRegisters(bool invalidate, bool clear_dirty) +{ + for (u8 reg = 0; reg < static_cast<u8>(Reg::count); reg++) + { + const Value& gr = m_state.guest_reg_state[reg]; + if (!gr.IsInHostRegister() || + (m_state.host_reg_state[gr.GetHostRegister()] & HostRegState::CallerSaved) != HostRegState::CallerSaved) + { + continue; + } + + FlushGuestRegister(static_cast<Reg>(reg), invalidate, clear_dirty); + } +} + bool RegisterCache::EvictOneGuestRegister() { if (m_state.guest_reg_order_count == 0) diff --git a/src/core/cpu_recompiler_register_cache.h b/src/core/cpu_recompiler_register_cache.h index 4bc8dee19..0c989f296 100644 --- a/src/core/cpu_recompiler_register_cache.h +++ b/src/core/cpu_recompiler_register_cache.h @@ -316,6 +316,7 @@ public: void InvalidateAllNonDirtyGuestRegisters(); void FlushAllGuestRegisters(bool invalidate, bool clear_dirty); + void FlushCallerSavedGuestRegisters(bool invalidate, bool clear_dirty); bool EvictOneGuestRegister(); /// Temporarily prevents register allocation.