emit_arm64_a64: Take into account currently loaded FPSR

Previously we just retrieved the last stored FPSR and used that when the guest asks for the current FPSR.
This is incorrect behaviour. We failed to take into account the current state of the host FPSR.

Here we take this into account. This bug was discovered via #795.
This commit is contained in:
Merry 2024-02-13 02:19:38 +00:00
parent ba8192d890
commit 4ae4750b5a
3 changed files with 15 additions and 2 deletions

View file

@ -10,6 +10,7 @@
#include "dynarmic/backend/arm64/abi.h"
#include "dynarmic/backend/arm64/emit_arm64.h"
#include "dynarmic/backend/arm64/emit_context.h"
#include "dynarmic/backend/arm64/fpsr_manager.h"
#include "dynarmic/backend/arm64/reg_alloc.h"
#include "dynarmic/interface/halt_reason.h"
#include "dynarmic/ir/basic_block.h"
@ -277,11 +278,11 @@ void EmitIR<IR::Opcode::A64GetFPCR>(oaknut::CodeGenerator& code, EmitContext& ct
}
template<>
void EmitIR<IR::Opcode::A64GetFPSR>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
void EmitIR<IR::Opcode::A64GetFPSR>(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst) {
auto Wresult = ctx.reg_alloc.WriteW(inst);
RegAlloc::Realize(Wresult);
code.LDR(Wresult, Xstate, offsetof(A64JitState, fpsr));
ctx.fpsr.GetFpsr(Wresult);
}
template<>

View file

@ -37,4 +37,13 @@ void FpsrManager::Load() {
fpsr_loaded = true;
}
void FpsrManager::GetFpsr(oaknut::WReg dest) {
code.LDR(dest, Xstate, state_fpsr_offset);
if (fpsr_loaded) {
code.MRS(Xscratch1, oaknut::SystemReg::FPSR);
code.ORR(dest, dest, Wscratch1);
}
}
} // namespace Dynarmic::Backend::Arm64

View file

@ -9,6 +9,7 @@
namespace oaknut {
struct CodeGenerator;
struct WReg;
} // namespace oaknut
namespace Dynarmic::Backend::Arm64 {
@ -21,6 +22,8 @@ public:
void Load();
void Overwrite() { fpsr_loaded = false; }
void GetFpsr(oaknut::WReg);
private:
oaknut::CodeGenerator& code;
size_t state_fpsr_offset;