@@ -75,12 +75,13 @@ void JitArm64::lfXX(UGeckoInstruction inst)
u32 imm_addr = 0;
bool is_immediate = false;

RegType type = !!(flags & BackPatchInfo::FLAG_SIZE_F64) ? REG_LOWER_PAIR : REG_DUP_SINGLE;
const RegType type =
(flags & BackPatchInfo::FLAG_SIZE_F64) != 0 ? RegType::LowerPair : RegType::DuplicatedSingle;

gpr.Lock(W0, W30);
fpr.Lock(Q0);

ARM64Reg VD = fpr.RW(inst.FD, type);
const ARM64Reg VD = fpr.RW(inst.FD, type);
ARM64Reg addr_reg = W0;

if (update)
@@ -244,9 +245,9 @@ void JitArm64::stfXX(UGeckoInstruction inst)
gpr.Lock(W0, W1, W30);
fpr.Lock(Q0);

bool single = (flags & BackPatchInfo::FLAG_SIZE_F32) && fpr.IsSingle(inst.FS, true);
const bool single = (flags & BackPatchInfo::FLAG_SIZE_F32) && fpr.IsSingle(inst.FS, true);

ARM64Reg V0 = fpr.R(inst.FS, single ? REG_LOWER_PAIR_SINGLE : REG_LOWER_PAIR);
const ARM64Reg V0 = fpr.R(inst.FS, single ? RegType::LowerPairSingle : RegType::LowerPair);

if (single)
{
@@ -31,16 +31,16 @@ void JitArm64::psq_l(UGeckoInstruction inst)
// X2 is a temporary
// Q0 is the return register
// Q1 is a temporary
bool update = inst.OPCD == 57;
s32 offset = inst.SIMM_12;
const bool update = inst.OPCD == 57;
const s32 offset = inst.SIMM_12;

gpr.Lock(W0, W1, W2, W30);
fpr.Lock(Q0, Q1);

ARM64Reg arm_addr = gpr.R(inst.RA);
ARM64Reg scale_reg = W0;
ARM64Reg addr_reg = W1;
ARM64Reg type_reg = W2;
const ARM64Reg arm_addr = gpr.R(inst.RA);
constexpr ARM64Reg scale_reg = W0;
constexpr ARM64Reg addr_reg = W1;
constexpr ARM64Reg type_reg = W2;
ARM64Reg VS;

if (inst.RA || update) // Always uses the register on update
@@ -57,13 +57,13 @@ void JitArm64::psq_l(UGeckoInstruction inst)

if (update)
{
gpr.BindToRegister(inst.RA, REG_REG);
gpr.BindToRegister(inst.RA, true);
MOV(arm_addr, addr_reg);
}

if (js.assumeNoPairedQuantize)
{
VS = fpr.RW(inst.RS, REG_REG_SINGLE);
VS = fpr.RW(inst.RS, RegType::Single);
if (!inst.W)
{
ADD(EncodeRegTo64(addr_reg), EncodeRegTo64(addr_reg), MEM_REG);
@@ -85,7 +85,7 @@ void JitArm64::psq_l(UGeckoInstruction inst)
LDR(X30, X30, ArithOption(EncodeRegTo64(type_reg), true));
BLR(X30);

VS = fpr.RW(inst.RS, REG_REG_SINGLE);
VS = fpr.RW(inst.RS, RegType::Single);
m_float_emit.ORR(EncodeRegToDouble(VS), D0, D0);
}

@@ -113,20 +113,20 @@ void JitArm64::psq_st(UGeckoInstruction inst)
// X1 is the address
// Q0 is the store register

bool update = inst.OPCD == 61;
s32 offset = inst.SIMM_12;
const bool update = inst.OPCD == 61;
const s32 offset = inst.SIMM_12;

gpr.Lock(W0, W1, W2, W30);
fpr.Lock(Q0, Q1);

bool single = fpr.IsSingle(inst.RS);
const bool single = fpr.IsSingle(inst.RS);

ARM64Reg arm_addr = gpr.R(inst.RA);
ARM64Reg VS = fpr.R(inst.RS, single ? REG_REG_SINGLE : REG_REG);
const ARM64Reg arm_addr = gpr.R(inst.RA);
const ARM64Reg VS = fpr.R(inst.RS, single ? RegType::Single : RegType::Register);

ARM64Reg scale_reg = W0;
ARM64Reg addr_reg = W1;
ARM64Reg type_reg = W2;
constexpr ARM64Reg scale_reg = W0;
constexpr ARM64Reg addr_reg = W1;
constexpr ARM64Reg type_reg = W2;

BitSet32 gprs_in_use = gpr.GetCallerSavedUsed();
BitSet32 fprs_in_use = fpr.GetCallerSavedUsed();
@@ -149,7 +149,7 @@ void JitArm64::psq_st(UGeckoInstruction inst)

if (update)
{
gpr.BindToRegister(inst.RA, REG_REG);
gpr.BindToRegister(inst.RA, true);
MOV(arm_addr, addr_reg);
}

@@ -22,16 +22,18 @@ void JitArm64::ps_mergeXX(UGeckoInstruction inst)
JITDISABLE(bJITPairedOff);
FALLBACK_IF(inst.Rc);

u32 a = inst.FA, b = inst.FB, d = inst.FD;
const u32 a = inst.FA;
const u32 b = inst.FB;
const u32 d = inst.FD;

bool singles = fpr.IsSingle(a) && fpr.IsSingle(b);
RegType type = singles ? REG_REG_SINGLE : REG_REG;
u8 size = singles ? 32 : 64;
ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad;
const bool singles = fpr.IsSingle(a) && fpr.IsSingle(b);
const RegType type = singles ? RegType::Single : RegType::Register;
const u8 size = singles ? 32 : 64;
const auto reg_encoder = singles ? EncodeRegToDouble : EncodeRegToQuad;

ARM64Reg VA = fpr.R(a, type);
ARM64Reg VB = fpr.R(b, type);
ARM64Reg VD = fpr.RW(d, type);
const ARM64Reg VA = fpr.R(a, type);
const ARM64Reg VB = fpr.R(b, type);
const ARM64Reg VD = fpr.RW(d, type);

switch (inst.SUBOP10)
{
@@ -73,18 +75,20 @@ void JitArm64::ps_mulsX(UGeckoInstruction inst)
FALLBACK_IF(inst.Rc);
FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF);

u32 a = inst.FA, c = inst.FC, d = inst.FD;
const u32 a = inst.FA;
const u32 c = inst.FC;
const u32 d = inst.FD;

bool upper = inst.SUBOP5 == 13;
const bool upper = inst.SUBOP5 == 13;

bool singles = fpr.IsSingle(a) && fpr.IsSingle(c);
RegType type = singles ? REG_REG_SINGLE : REG_REG;
u8 size = singles ? 32 : 64;
ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad;
const bool singles = fpr.IsSingle(a) && fpr.IsSingle(c);
const RegType type = singles ? RegType::Single : RegType::Register;
const u8 size = singles ? 32 : 64;
const auto reg_encoder = singles ? EncodeRegToDouble : EncodeRegToQuad;

ARM64Reg VA = fpr.R(a, type);
ARM64Reg VC = fpr.R(c, type);
ARM64Reg VD = fpr.RW(d, type);
const ARM64Reg VA = fpr.R(a, type);
const ARM64Reg VC = fpr.R(c, type);
const ARM64Reg VD = fpr.RW(d, type);

m_float_emit.FMUL(size, reg_encoder(VD), reg_encoder(VA), reg_encoder(VC), upper ? 1 : 0);

@@ -98,18 +102,21 @@ void JitArm64::ps_maddXX(UGeckoInstruction inst)
FALLBACK_IF(inst.Rc);
FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF);

u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD;
u32 op5 = inst.SUBOP5;

bool singles = fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c);
RegType type = singles ? REG_REG_SINGLE : REG_REG;
u8 size = singles ? 32 : 64;
ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad;

ARM64Reg VA = reg_encoder(fpr.R(a, type));
ARM64Reg VB = reg_encoder(fpr.R(b, type));
ARM64Reg VC = reg_encoder(fpr.R(c, type));
ARM64Reg VD = reg_encoder(fpr.RW(d, type));
const u32 a = inst.FA;
const u32 b = inst.FB;
const u32 c = inst.FC;
const u32 d = inst.FD;
const u32 op5 = inst.SUBOP5;

const bool singles = fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c);
const RegType type = singles ? RegType::Single : RegType::Register;
const u8 size = singles ? 32 : 64;
const auto reg_encoder = singles ? EncodeRegToDouble : EncodeRegToQuad;

const ARM64Reg VA = reg_encoder(fpr.R(a, type));
const ARM64Reg VB = reg_encoder(fpr.R(b, type));
const ARM64Reg VC = reg_encoder(fpr.R(c, type));
const ARM64Reg VD = reg_encoder(fpr.RW(d, type));
ARM64Reg V0Q = INVALID_REG;
ARM64Reg V0 = INVALID_REG;
if (d != b && (d == a || d == c))
@@ -255,17 +262,20 @@ void JitArm64::ps_sel(UGeckoInstruction inst)
JITDISABLE(bJITPairedOff);
FALLBACK_IF(inst.Rc);

u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD;
const u32 a = inst.FA;
const u32 b = inst.FB;
const u32 c = inst.FC;
const u32 d = inst.FD;

bool singles = fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c);
RegType type = singles ? REG_REG_SINGLE : REG_REG;
u8 size = singles ? 32 : 64;
ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad;
const bool singles = fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c);
const RegType type = singles ? RegType::Single : RegType::Register;
const u8 size = singles ? 32 : 64;
const auto reg_encoder = singles ? EncodeRegToDouble : EncodeRegToQuad;

ARM64Reg VA = reg_encoder(fpr.R(a, type));
ARM64Reg VB = reg_encoder(fpr.R(b, type));
ARM64Reg VC = reg_encoder(fpr.R(c, type));
ARM64Reg VD = reg_encoder(fpr.RW(d, type));
const ARM64Reg VA = reg_encoder(fpr.R(a, type));
const ARM64Reg VB = reg_encoder(fpr.R(b, type));
const ARM64Reg VC = reg_encoder(fpr.R(c, type));
const ARM64Reg VD = reg_encoder(fpr.RW(d, type));

if (d != b && d != c)
{
@@ -274,8 +284,8 @@ void JitArm64::ps_sel(UGeckoInstruction inst)
}
else
{
ARM64Reg V0Q = fpr.GetReg();
ARM64Reg V0 = reg_encoder(V0Q);
const ARM64Reg V0Q = fpr.GetReg();
const ARM64Reg V0 = reg_encoder(V0Q);
m_float_emit.FCMGE(size, V0, VA);
m_float_emit.BSL(V0, VC, VB);
m_float_emit.MOV(VD, V0);
@@ -290,20 +300,23 @@ void JitArm64::ps_sumX(UGeckoInstruction inst)
FALLBACK_IF(inst.Rc);
FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF);

u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD;
const u32 a = inst.FA;
const u32 b = inst.FB;
const u32 c = inst.FC;
const u32 d = inst.FD;

bool upper = inst.SUBOP5 == 11;
const bool upper = inst.SUBOP5 == 11;

bool singles = fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c);
RegType type = singles ? REG_REG_SINGLE : REG_REG;
u8 size = singles ? 32 : 64;
ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad;
const bool singles = fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c);
const RegType type = singles ? RegType::Single : RegType::Register;
const u8 size = singles ? 32 : 64;
const auto reg_encoder = singles ? EncodeRegToDouble : EncodeRegToQuad;

ARM64Reg VA = fpr.R(a, type);
ARM64Reg VB = fpr.R(b, type);
ARM64Reg VC = fpr.R(c, type);
ARM64Reg VD = fpr.RW(d, type);
ARM64Reg V0 = fpr.GetReg();
const ARM64Reg VA = fpr.R(a, type);
const ARM64Reg VB = fpr.R(b, type);
const ARM64Reg VC = fpr.R(c, type);
const ARM64Reg VD = fpr.RW(d, type);
const ARM64Reg V0 = fpr.GetReg();

m_float_emit.DUP(size, reg_encoder(V0), reg_encoder(upper ? VA : VB), upper ? 0 : 1);
if (d != c)

Large diffs are not rendered by default.

@@ -15,10 +15,13 @@
#include "Core/PowerPC/PowerPC.h"

// Dedicated host registers
static const Arm64Gen::ARM64Reg MEM_REG = Arm64Gen::X28; // memory base register
static const Arm64Gen::ARM64Reg PPC_REG = Arm64Gen::X29; // ppcState pointer
static const Arm64Gen::ARM64Reg DISPATCHER_PC =
Arm64Gen::W26; // PC register when calling the dispatcher

// memory base register
constexpr Arm64Gen::ARM64Reg MEM_REG = Arm64Gen::X28;
// ppcState pointer
constexpr Arm64Gen::ARM64Reg PPC_REG = Arm64Gen::X29;
// PC register when calling the dispatcher
constexpr Arm64Gen::ARM64Reg DISPATCHER_PC = Arm64Gen::W26;

#define PPCSTATE_OFF(elem) (offsetof(PowerPC::PowerPCState, elem))

@@ -29,51 +32,52 @@ static_assert((PPCSTATE_OFF(ps[0].ps0) % 8) == 0,
static_assert(PPCSTATE_OFF(xer_ca) < 4096, "STRB can't store xer_ca!");
static_assert(PPCSTATE_OFF(xer_so_ov) < 4096, "STRB can't store xer_so_ov!");

enum RegType
enum class RegType
{
REG_NOTLOADED = 0,
REG_REG, // Reg type is register
REG_IMM, // Reg is really a IMM
REG_LOWER_PAIR, // Only the lower pair of a paired register
REG_DUP, // The lower reg is the same as the upper one (physical upper doesn't actually have the
// duplicated value)
REG_REG_SINGLE, // Both registers are loaded as single
REG_LOWER_PAIR_SINGLE, // Only the lower pair of a paired register, as single
REG_DUP_SINGLE, // The lower one contains both registers, as single
NotLoaded,
Register, // Reg type is register
Immediate, // Reg is really a IMM
LowerPair, // Only the lower pair of a paired register
Duplicated, // The lower reg is the same as the upper one (physical upper doesn't actually have
// the duplicated value)
Single, // Both registers are loaded as single
LowerPairSingle, // Only the lower pair of a paired register, as single
DuplicatedSingle, // The lower one contains both registers, as single
};

enum FlushMode
enum class FlushMode
{
// Flushes all registers, no exceptions
FLUSH_ALL = 0,
All,
// Flushes registers in a conditional branch
// Doesn't wipe the state of the registers from the cache
FLUSH_MAINTAIN_STATE,
MaintainState,
};

class OpArg
{
public:
OpArg() : m_type(REG_NOTLOADED), m_reg(Arm64Gen::INVALID_REG), m_value(0), m_last_used(0) {}
OpArg() = default;

RegType GetType() const { return m_type; }
Arm64Gen::ARM64Reg GetReg() const { return m_reg; }
u32 GetImm() const { return m_value; }
void Load(Arm64Gen::ARM64Reg reg, RegType type = REG_REG)
void Load(Arm64Gen::ARM64Reg reg, RegType type = RegType::Register)
{
m_type = type;
m_reg = reg;
}
void LoadToImm(u32 imm)
{
m_type = REG_IMM;
m_type = RegType::Immediate;
m_value = imm;

m_reg = Arm64Gen::INVALID_REG;
}
void Flush()
{
// Invalidate any previous information
m_type = REG_NOTLOADED;
m_type = RegType::NotLoaded;
m_reg = Arm64Gen::INVALID_REG;

// Arbitrarily large value that won't roll over on a lot of increments
@@ -88,48 +92,49 @@ class OpArg

private:
// For REG_REG
RegType m_type; // store type
Arm64Gen::ARM64Reg m_reg; // host register we are in
RegType m_type = RegType::NotLoaded; // store type
Arm64Gen::ARM64Reg m_reg = Arm64Gen::INVALID_REG; // host register we are in

// For REG_IMM
u32 m_value; // IMM value
u32 m_value = 0; // IMM value

u32 m_last_used;
u32 m_last_used = 0;

bool m_dirty;
bool m_dirty = false;
};

class HostReg
{
public:
HostReg() : m_reg(Arm64Gen::INVALID_REG), m_locked(false) {}
HostReg(Arm64Gen::ARM64Reg reg) : m_reg(reg), m_locked(false) {}
HostReg() = default;
HostReg(Arm64Gen::ARM64Reg reg) : m_reg(reg) {}

bool IsLocked() const { return m_locked; }
void Lock() { m_locked = true; }
void Unlock() { m_locked = false; }
Arm64Gen::ARM64Reg GetReg() const { return m_reg; }
bool operator==(const Arm64Gen::ARM64Reg& reg) { return reg == m_reg; }

bool operator==(Arm64Gen::ARM64Reg reg) const { return reg == m_reg; }
bool operator!=(Arm64Gen::ARM64Reg reg) const { return !operator==(reg); }

private:
Arm64Gen::ARM64Reg m_reg;
bool m_locked;
Arm64Gen::ARM64Reg m_reg = Arm64Gen::INVALID_REG;
bool m_locked = false;
};

class Arm64RegCache
{
public:
explicit Arm64RegCache(size_t guest_reg_count)
: m_emit(nullptr), m_float_emit(nullptr), m_guest_registers(guest_reg_count),
m_reg_stats(nullptr){};
virtual ~Arm64RegCache(){};
explicit Arm64RegCache(size_t guest_reg_count) : m_guest_registers(guest_reg_count) {}
virtual ~Arm64RegCache() = default;

void Init(Arm64Gen::ARM64XEmitter* emitter);

virtual void Start(PPCAnalyst::BlockRegStats& stats) {}
// Flushes the register cache in different ways depending on the mode
virtual void Flush(FlushMode mode, PPCAnalyst::CodeOp* op) = 0;

virtual BitSet32 GetCallerSavedUsed() = 0;
virtual BitSet32 GetCallerSavedUsed() const = 0;

// Returns a temporary register for use
// Requires unlocking after done
@@ -178,7 +183,7 @@ class Arm64RegCache
virtual void FlushRegister(size_t preg, bool maintain_state) = 0;

// Get available host registers
u32 GetUnlockedRegisterCount();
u32 GetUnlockedRegisterCount() const;

void IncrementAllUsed()
{
@@ -187,7 +192,7 @@ class Arm64RegCache
}

// Code emitter
Arm64Gen::ARM64XEmitter* m_emit;
Arm64Gen::ARM64XEmitter* m_emit = nullptr;

// Float emitter
std::unique_ptr<Arm64Gen::ARM64FloatEmitter> m_float_emit;
@@ -201,14 +206,14 @@ class Arm64RegCache
std::vector<OpArg> m_guest_registers;

// Register stats for the current block
PPCAnalyst::BlockRegStats* m_reg_stats;
PPCAnalyst::BlockRegStats* m_reg_stats = nullptr;
};

class Arm64GPRCache : public Arm64RegCache
{
public:
Arm64GPRCache();
~Arm64GPRCache() {}

void Start(PPCAnalyst::BlockRegStats& stats) override;

// Flushes the register cache in different ways depending on the mode
@@ -222,14 +227,14 @@ class Arm64GPRCache : public Arm64RegCache
// Set a register to an immediate, only valid for guest GPRs
void SetImmediate(size_t preg, u32 imm) { SetImmediate(GetGuestGPR(preg), imm); }
// Returns if a register is set as an immediate, only valid for guest GPRs
bool IsImm(size_t preg) const { return GetGuestGPROpArg(preg).GetType() == REG_IMM; }
bool IsImm(size_t preg) const { return GetGuestGPROpArg(preg).GetType() == RegType::Immediate; }
// Gets the immediate that a register is set to, only valid for guest GPRs
u32 GetImm(size_t preg) const { return GetGuestGPROpArg(preg).GetImm(); }
// Binds a guest GPR to a host register, optionally loading its value
void BindToRegister(size_t preg, bool do_load) { BindToRegister(GetGuestGPR(preg), do_load); }
// Binds a guest CR to a host register, optionally loading its value
void BindCRToRegister(size_t preg, bool do_load) { BindToRegister(GetGuestCR(preg), do_load); }
BitSet32 GetCallerSavedUsed() override;
BitSet32 GetCallerSavedUsed() const override;

void StoreRegisters(BitSet32 regs) { FlushRegisters(regs, false); }
void StoreCRRegisters(BitSet32 regs) { FlushCRRegisters(regs, false); }
@@ -244,7 +249,7 @@ class Arm64GPRCache : public Arm64RegCache
void FlushRegister(size_t index, bool maintain_state) override;

private:
bool IsCalleeSaved(Arm64Gen::ARM64Reg reg);
bool IsCalleeSaved(Arm64Gen::ARM64Reg reg) const;

struct GuestRegInfo
{
@@ -270,19 +275,19 @@ class Arm64FPRCache : public Arm64RegCache
{
public:
Arm64FPRCache();
~Arm64FPRCache() {}

// Flushes the register cache in different ways depending on the mode
void Flush(FlushMode mode, PPCAnalyst::CodeOp* op = nullptr) override;

// Returns a guest register inside of a host register
// Will dump an immediate to the host register as well
Arm64Gen::ARM64Reg R(size_t preg, RegType type = REG_LOWER_PAIR);
Arm64Gen::ARM64Reg R(size_t preg, RegType type = RegType::LowerPair);

Arm64Gen::ARM64Reg RW(size_t preg, RegType type = REG_LOWER_PAIR);
Arm64Gen::ARM64Reg RW(size_t preg, RegType type = RegType::LowerPair);

BitSet32 GetCallerSavedUsed() override;
BitSet32 GetCallerSavedUsed() const override;

bool IsSingle(size_t preg, bool lower_only = false);
bool IsSingle(size_t preg, bool lower_only = false) const;

void FixSinglePrecision(size_t preg);

@@ -298,7 +303,7 @@ class Arm64FPRCache : public Arm64RegCache
void FlushRegister(size_t preg, bool maintain_state) override;

private:
bool IsCalleeSaved(Arm64Gen::ARM64Reg reg);
bool IsCalleeSaved(Arm64Gen::ARM64Reg reg) const;

void FlushRegisters(BitSet32 regs, bool maintain_state);
};
@@ -44,8 +44,8 @@ void JitArm64::mtmsr(UGeckoInstruction inst)
gpr.BindToRegister(inst.RS, true);
STR(INDEX_UNSIGNED, gpr.R(inst.RS), PPC_REG, PPCSTATE_OFF(msr));

gpr.Flush(FlushMode::FLUSH_ALL);
fpr.Flush(FlushMode::FLUSH_ALL);
gpr.Flush(FlushMode::All);
fpr.Flush(FlushMode::All);

// Our jit cache also stores some MSR bits, as they have changed, we either
// have to validate them in the BLR/RET check, or just flush the stack here.
@@ -201,8 +201,8 @@ void JitArm64::twx(UGeckoInstruction inst)
SwitchToFarCode();
SetJumpTarget(far_addr);

gpr.Flush(FlushMode::FLUSH_MAINTAIN_STATE);
fpr.Flush(FlushMode::FLUSH_MAINTAIN_STATE);
gpr.Flush(FlushMode::MaintainState);
fpr.Flush(FlushMode::MaintainState);

LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions));
ORR(WA, WA, 24, 0); // Same as WA | EXCEPTION_PROGRAM
@@ -217,8 +217,8 @@ void JitArm64::twx(UGeckoInstruction inst)

if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE))
{
gpr.Flush(FlushMode::FLUSH_ALL);
fpr.Flush(FlushMode::FLUSH_ALL);
gpr.Flush(FlushMode::All);
fpr.Flush(FlushMode::All);
WriteExit(js.compilerPC + 4);
}
}