Jit: Update constant propagation during instruction

This commit makes the JIT set/clear the individual registers of
ConstantPropagation immediately instead of at the end of the
instruction. This is needed to prevent Jit64::ComputeRC, which reads
from a register written to earlier during the same instruction, from
reading back stale register values from ConstantPropagation in the next
commit.
This commit is contained in:
JosJuice 2024-09-01 16:10:17 +02:00
parent b5ad740d55
commit db6bf3bfa8
11 changed files with 33 additions and 9 deletions

View file

@ -370,6 +370,9 @@ void Jit64::FallBackToInterpreter(UGeckoInstruction inst)
gpr.Reset(js.op->regsOut);
fpr.Reset(js.op->GetFregsOut());
// We must also update constant propagation
m_constant_propagation.ClearGPRs(js.op->regsOut);
if (js.op->canEndBlock)
{
if (js.isLastInstruction)
@ -1127,8 +1130,6 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
}
CompileInstruction(op);
m_constant_propagation.ClearGPRs(op.regsOut);
}
m_constant_propagation.Apply(constant_propagation_result);

View file

@ -82,6 +82,8 @@ public:
void IntializeSpeculativeConstants();
JitCommon::ConstantPropagation& GetConstantPropagation() { return m_constant_propagation; }
JitBlockCache* GetBlockCache() override { return &blocks; }
void Trace();

View file

@ -25,6 +25,11 @@ void FPURegCache::LoadRegister(preg_t preg, X64Reg new_loc)
m_emitter->MOVAPD(new_loc, m_regs[preg].Location().value());
}
void FPURegCache::DiscardImm(preg_t preg)
{
// FPURegCache doesn't support immediates, so no need to do anything
}
std::span<const X64Reg> FPURegCache::GetAllocationOrder() const
{
static constexpr X64Reg allocation_order[] = {XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12,

View file

@ -16,6 +16,7 @@ protected:
Gen::OpArg GetDefaultLocation(preg_t preg) const override;
void StoreRegister(preg_t preg, const Gen::OpArg& newLoc) override;
void LoadRegister(preg_t preg, Gen::X64Reg newLoc) override;
void DiscardImm(preg_t preg) override;
std::span<const Gen::X64Reg> GetAllocationOrder() const override;
BitSet32 GetRegUtilization() const override;
BitSet32 CountRegsIn(preg_t preg, u32 lookahead) const override;

View file

@ -25,6 +25,11 @@ void GPRRegCache::LoadRegister(preg_t preg, X64Reg new_loc)
m_emitter->MOV(32, ::Gen::R(new_loc), m_regs[preg].Location().value());
}
void GPRRegCache::DiscardImm(preg_t preg)
{
m_jit.GetConstantPropagation().ClearGPR(preg);
}
OpArg GPRRegCache::GetDefaultLocation(preg_t preg) const
{
return PPCSTATE_GPR(preg);
@ -50,6 +55,7 @@ void GPRRegCache::SetImmediate32(preg_t preg, u32 imm_value, bool dirty)
// processing speculative constants.
DiscardRegContentsIfCached(preg);
m_regs[preg].SetToImm32(imm_value, dirty);
m_jit.GetConstantPropagation().SetGPR(preg, imm_value);
}
BitSet32 GPRRegCache::GetRegUtilization() const

View file

@ -17,6 +17,7 @@ protected:
Gen::OpArg GetDefaultLocation(preg_t preg) const override;
void StoreRegister(preg_t preg, const Gen::OpArg& new_loc) override;
void LoadRegister(preg_t preg, Gen::X64Reg new_loc) override;
void DiscardImm(preg_t preg) override;
std::span<const Gen::X64Reg> GetAllocationOrder() const override;
BitSet32 GetRegUtilization() const override;
BitSet32 CountRegsIn(preg_t preg, u32 lookahead) const override;

View file

@ -536,6 +536,9 @@ void RegCache::BindToRegister(preg_t i, bool doLoad, bool makeDirty)
m_xregs[RX(i)].MakeDirty();
}
if (makeDirty)
DiscardImm(i);
ASSERT_MSG(DYNA_REC, !m_xregs[RX(i)].IsLocked(),
"WTF, this reg ({} -> {}) should have been flushed", i, Common::ToUnderlying(RX(i)));
}

View file

@ -193,6 +193,7 @@ protected:
virtual Gen::OpArg GetDefaultLocation(preg_t preg) const = 0;
virtual void StoreRegister(preg_t preg, const Gen::OpArg& new_loc) = 0;
virtual void LoadRegister(preg_t preg, Gen::X64Reg new_loc) = 0;
virtual void DiscardImm(preg_t preg) = 0;
virtual std::span<const Gen::X64Reg> GetAllocationOrder() const = 0;

View file

@ -279,6 +279,9 @@ void JitArm64::FallBackToInterpreter(UGeckoInstruction inst)
fpr.ResetRegisters(js.op->GetFregsOut());
gpr.ResetCRRegisters(js.op->crOut);
// We must also update constant propagation
m_constant_propagation.ClearGPRs(js.op->regsOut);
if (js.op->canEndBlock)
{
if (js.isLastInstruction)
@ -1351,12 +1354,8 @@ bool JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
m_constant_propagation.EvaluateInstruction(op.inst, opinfo->flags);
if (!constant_propagation_result.instruction_fully_executed)
{
CompileInstruction(op);
m_constant_propagation.ClearGPRs(op.regsOut);
}
m_constant_propagation.Apply(constant_propagation_result);
if (constant_propagation_result.gpr >= 0)

View file

@ -36,6 +36,8 @@ public:
void Init() override;
void Shutdown() override;
JitCommon::ConstantPropagation& GetConstantPropagation() { return m_constant_propagation; }
JitBaseBlockCache* GetBlockCache() override { return &blocks; }
bool IsInCodeSpace(const u8* ptr) const { return IsInSpace(ptr); }
bool HandleFault(uintptr_t access_address, SContext* ctx) override;

View file

@ -378,6 +378,7 @@ void Arm64GPRCache::SetImmediateInternal(size_t index, u32 imm, bool dirty)
UnlockRegister(EncodeRegTo32(reg.GetReg()));
reg.LoadToImm(imm);
reg.SetDirty(dirty);
m_jit->GetConstantPropagation().SetGPR(index - GUEST_GPR_OFFSET, imm);
}
void Arm64GPRCache::BindForWrite(size_t index, bool will_read, bool will_write)
@ -385,6 +386,7 @@ void Arm64GPRCache::BindForWrite(size_t index, bool will_read, bool will_write)
GuestRegInfo guest_reg = GetGuestByIndex(index);
OpArg& reg = guest_reg.reg;
const size_t bitsize = guest_reg.bitsize;
const bool is_gpr = index >= GUEST_GPR_OFFSET && index < GUEST_GPR_OFFSET + GUEST_GPR_COUNT;
reg.ResetLastUsed();
@ -411,12 +413,13 @@ void Arm64GPRCache::BindForWrite(size_t index, bool will_read, bool will_write)
m_emit->MOVI2R(host_reg, reg.GetImm());
}
reg.Load(host_reg);
if (will_write)
reg.SetDirty(true);
}
else if (will_write)
if (will_write)
{
reg.SetDirty(true);
if (is_gpr)
m_jit->GetConstantPropagation().ClearGPR(index - GUEST_GPR_OFFSET);
}
}