From 4b4aa1cdbe4e0064638c740b66bc93ee8b499ccd Mon Sep 17 00:00:00 2001 From: LC Date: Thu, 16 Jul 2026 08:00:19 -0400 Subject: [PATCH] Arm64Emitter: Pull FillSpecialRegs bools into a struct Makes this easily expandable over time without modifying the prototype, and lets us be a little more informative at call sites. --- .../Interface/Core/ArchHelpers/Arm64Emitter.cpp | 8 ++++---- .../Interface/Core/ArchHelpers/Arm64Emitter.h | 14 +++++++++++++- .../Interface/Core/Dispatcher/Dispatcher.cpp | 2 +- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.cpp b/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.cpp index 8856b44bf..410865611 100644 --- a/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.cpp +++ b/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.cpp @@ -633,7 +633,7 @@ void Arm64Emitter::PopCalleeSavedRegisters() { } } -void Arm64Emitter::FillSpecialRegs(ARMEmitter::Register TmpReg, ARMEmitter::Register TmpReg2, bool SetFIZ, bool SetPredRegs) { +void Arm64Emitter::FillSpecialRegs(ARMEmitter::Register TmpReg, ARMEmitter::Register TmpReg2, const FillSpecialRegsOptions& Options) { #ifndef VIXL_SIMULATOR if (EmitterCTX->HostFeatures.SupportsAFP) { // Enable AFP features when filling JIT state. @@ -649,7 +649,7 @@ void Arm64Emitter::FillSpecialRegs(ARMEmitter::Register TmpReg, ARMEmitter::Regi (1U << 2) | // NEP (1U << 1)); // AH - if (SetFIZ) { + if (Options.SetFIZ) { // Insert MXCSR.DAZ in to FIZ ldr(TmpReg2.W(), STATE.R(), offsetof(FEXCore::Core::CPUState, mxcsr)); bfxil(ARMEmitter::Size::i64Bit, TmpReg, TmpReg2, 6, 1); @@ -659,7 +659,7 @@ void Arm64Emitter::FillSpecialRegs(ARMEmitter::Register TmpReg, ARMEmitter::Regi } #endif - if (SetPredRegs && EmitterCTX->HostFeatures.SupportsSVE()) { + if (Options.SetPredRegs && EmitterCTX->HostFeatures.SupportsSVE()) { // Set up predicate registers. // We don't bother spilling these in SpillStaticRegs, // since all that matters is we restore them on a fill. @@ -822,7 +822,7 @@ void Arm64Emitter::FillStaticRegs(FillStaticRegOptions Options) { msr(ARMEmitter::SystemRegister::NZCV, TmpReg); } - FillSpecialRegs(TmpReg, TmpReg2, true, Options.FPRs); + FillSpecialRegs(TmpReg, TmpReg2, {.SetFIZ = true, .SetPredRegs = Options.FPRs}); if (Options.FPRs) { if (EmitterCTX->HostFeatures.SupportsAVX && EmitterCTX->HostFeatures.SupportsSVE256) { diff --git a/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.h b/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.h index 5d1a61ee8..b4a48cc40 100644 --- a/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.h +++ b/FEXCore/Source/Interface/Core/ArchHelpers/Arm64Emitter.h @@ -129,7 +129,19 @@ protected: std::span GeneralFPRegisters {}; uint32_t PairRegisters = 0; - void FillSpecialRegs(ARMEmitter::Register TmpReg, ARMEmitter::Register TmpReg2, bool SetFIZ, bool SetPredRegs); + struct FillSpecialRegsOptions { + // Whether or not to set the FPCR.FIZ (flush inputs to zero) bit in the FPCR to + // the current value of the emulated MXCSR.DAZ bit. + // Will only attempt to do so, even when set to true, if and only if the host system + // supports FEAT_AFP. + bool SetFIZ {}; + + // Whether or not FillSpecialRegs should load our SVE predicate temporaries + // with certain canned values that accelerate some operations. Will (obviously) + // not load predicates, even if set to true, on host systems that do not support SVE. + bool SetPredRegs {}; + }; + void FillSpecialRegs(ARMEmitter::Register TmpReg, ARMEmitter::Register TmpReg2, const FillSpecialRegsOptions& Options); // Correlate an ARM register back to an x86 register index. // Returning REG_INVALID if there was no mapping. diff --git a/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.cpp b/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.cpp index 748597e15..b174dab3c 100644 --- a/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.cpp +++ b/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.cpp @@ -121,7 +121,7 @@ void Dispatcher::EmitDispatcher() { ldr(REG_CALLRET_SP, STATE_PTR(CpuStateFrame, State.callret_sp)); - FillSpecialRegs(TMP1, TMP2, false, true); + FillSpecialRegs(TMP1, TMP2, {.SetFIZ = false, .SetPredRegs = true}); // As ARM64EC uses this as an entrypoint for both guest calls and host returns, opportunistically try to return // using the call-ret stack to avoid unbalancing it.