From e75e7a0e43119c587ab10182f29269799f17695b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 24 May 2024 23:08:28 +0200 Subject: [PATCH 1/3] Add an optimizeForInterpreter flag --- Core/MIPS/ARM64/Arm64IRJit.cpp | 1 + Core/MIPS/IR/IRFrontend.cpp | 9 +++++++-- Core/MIPS/IR/IRInst.h | 1 + Core/MIPS/IR/IRJit.cpp | 3 +++ Core/MIPS/JitCommon/JitState.h | 4 ++-- Core/MIPS/RiscV/RiscVJit.cpp | 1 + Core/MIPS/x86/X64IRJit.cpp | 1 + 7 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Core/MIPS/ARM64/Arm64IRJit.cpp b/Core/MIPS/ARM64/Arm64IRJit.cpp index 10438af30b..26d9913bdc 100644 --- a/Core/MIPS/ARM64/Arm64IRJit.cpp +++ b/Core/MIPS/ARM64/Arm64IRJit.cpp @@ -44,6 +44,7 @@ Arm64JitBackend::Arm64JitBackend(JitOptions &jitopt, IRBlockCache &blocks) if (((intptr_t)Memory::base & 0x00000000FFFFFFFFUL) != 0) { jo.enablePointerify = false; } + jo.optimizeForInterpreter = false; #ifdef MASKED_PSP_MEMORY jo.enablePointerify = false; #endif diff --git a/Core/MIPS/IR/IRFrontend.cpp b/Core/MIPS/IR/IRFrontend.cpp index 2270484391..36efd6ad72 100644 --- a/Core/MIPS/IR/IRFrontend.cpp +++ b/Core/MIPS/IR/IRFrontend.cpp @@ -277,7 +277,7 @@ void IRFrontend::DoJit(u32 em_address, std::vector &instructions, u32 &m IRWriter simplified; IRWriter *code = &ir; if (!js.hadBreakpoints) { - static const IRPassFunc passes[] = { + std::vector passes{ &ApplyMemoryValidation, &RemoveLoadStoreLeftRight, &OptimizeFPMoves, @@ -288,7 +288,12 @@ void IRFrontend::DoJit(u32 em_address, std::vector &instructions, u32 &m // &MergeLoadStore, // &ThreeOpToTwoOp, }; - if (IRApplyPasses(passes, ARRAY_SIZE(passes), ir, simplified, opts)) + + if (opts.optimizeForInterpreter) { + // Add special passes here. + // passes.push_back(&ReorderLoadStore); + } + if (IRApplyPasses(passes.data(), passes.size(), ir, simplified, opts)) logBlocks = 1; code = &simplified; //if (ir.GetInstructions().size() >= 24) diff --git a/Core/MIPS/IR/IRInst.h b/Core/MIPS/IR/IRInst.h index cec31c7ee3..e2d855a3e0 100644 --- a/Core/MIPS/IR/IRInst.h +++ b/Core/MIPS/IR/IRInst.h @@ -405,6 +405,7 @@ struct IROptions { bool unalignedLoadStoreVec4; bool preferVec4; bool preferVec4Dot; + bool optimizeForInterpreter; }; const IRMeta *GetIRMeta(IROp op); diff --git a/Core/MIPS/IR/IRJit.cpp b/Core/MIPS/IR/IRJit.cpp index c89c5fa41f..f3ce1c008b 100644 --- a/Core/MIPS/IR/IRJit.cpp +++ b/Core/MIPS/IR/IRJit.cpp @@ -48,6 +48,8 @@ IRJit::IRJit(MIPSState *mipsState) : frontend_(mipsState->HasDefaultPrefix()), m // blTrampolines_ = kernelMemory.Alloc(size, true, "trampoline"); InitIR(); + jo.optimizeForInterpreter = true; + IROptions opts{}; opts.disableFlags = g_Config.uJitDisableFlags; #if PPSSPP_ARCH(RISCV64) @@ -65,6 +67,7 @@ IRJit::IRJit(MIPSState *mipsState) : frontend_(mipsState->HasDefaultPrefix()), m opts.unalignedLoadStoreVec4 = false; opts.preferVec4 = true; #endif + opts.optimizeForInterpreter = jo.optimizeForInterpreter; frontend_.SetOptions(opts); } diff --git a/Core/MIPS/JitCommon/JitState.h b/Core/MIPS/JitCommon/JitState.h index 37acde3b62..6f5b9f2628 100644 --- a/Core/MIPS/JitCommon/JitState.h +++ b/Core/MIPS/JitCommon/JitState.h @@ -237,6 +237,8 @@ namespace MIPSComp { // ARM64 and RV64 bool useStaticAlloc; bool enablePointerify; + // IR Interpreter + bool optimizeForInterpreter; // Common bool enableBlocklink; @@ -245,6 +247,4 @@ namespace MIPSComp { bool continueJumps; int continueMaxInstructions; }; - } - diff --git a/Core/MIPS/RiscV/RiscVJit.cpp b/Core/MIPS/RiscV/RiscVJit.cpp index 60d5c5f929..65ebffc7b9 100644 --- a/Core/MIPS/RiscV/RiscVJit.cpp +++ b/Core/MIPS/RiscV/RiscVJit.cpp @@ -39,6 +39,7 @@ RiscVJitBackend::RiscVJitBackend(JitOptions &jitopt, IRBlockCache &blocks) if (((intptr_t)Memory::base & 0x00000000FFFFFFFFUL) != 0) { jo.enablePointerify = false; } + jo.optimizeForInterpreter = false; // Since we store the offset, this is as big as it can be. // We could shift off one bit to double it, would need to change RiscVAsm. diff --git a/Core/MIPS/x86/X64IRJit.cpp b/Core/MIPS/x86/X64IRJit.cpp index dbcddee3f5..be6a374697 100644 --- a/Core/MIPS/x86/X64IRJit.cpp +++ b/Core/MIPS/x86/X64IRJit.cpp @@ -41,6 +41,7 @@ X64JitBackend::X64JitBackend(JitOptions &jitopt, IRBlockCache &blocks) if (((intptr_t)Memory::base & 0x00000000FFFFFFFFUL) != 0) { jo.enablePointerify = false; } + jo.optimizeForInterpreter = false; // Since we store the offset, this is as big as it can be. AllocCodeSpace(1024 * 1024 * 16); From 7464b5f17bdf326506402cf7e4993129b65788b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 24 May 2024 23:11:46 +0200 Subject: [PATCH 2/3] IRInterpreter: Enable some optimizations that accidentally were only enabled on non-ARM64. --- Core/MIPS/IR/IRJit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/MIPS/IR/IRJit.cpp b/Core/MIPS/IR/IRJit.cpp index f3ce1c008b..d41656c107 100644 --- a/Core/MIPS/IR/IRJit.cpp +++ b/Core/MIPS/IR/IRJit.cpp @@ -57,7 +57,7 @@ IRJit::IRJit(MIPSState *mipsState) : frontend_(mipsState->HasDefaultPrefix()), m opts.unalignedLoadStore = false; opts.unalignedLoadStoreVec4 = true; opts.preferVec4 = cpu_info.RiscV_V; -#elif PPSSPP_ARCH(ARM) +#elif PPSSPP_ARCH(ARM) || PPSSPP_ARCH(ARM64) opts.unalignedLoadStore = (opts.disableFlags & (uint32_t)JitDisable::LSU_UNALIGNED) == 0; opts.unalignedLoadStoreVec4 = true; opts.preferVec4 = cpu_info.bASIMD || cpu_info.bNEON; From f2837e3b55b1d426790732bc26f7312b3cbf89aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 26 May 2024 13:57:08 +0200 Subject: [PATCH 3/3] JIT compare screen with IR blocks - fix some crashing issues --- Core/MIPS/IR/IRJit.cpp | 2 +- Core/MIPS/IR/IRJit.h | 24 ++++++++++++++---------- Core/MIPS/IR/IRNativeCommon.cpp | 4 ++++ Core/MIPS/IR/IRNativeCommon.h | 9 +++++---- Core/MIPS/JitCommon/JitBlockCache.h | 2 ++ UI/DevScreens.cpp | 11 ++++++++++- 6 files changed, 36 insertions(+), 16 deletions(-) diff --git a/Core/MIPS/IR/IRJit.cpp b/Core/MIPS/IR/IRJit.cpp index d41656c107..3bf42f33c8 100644 --- a/Core/MIPS/IR/IRJit.cpp +++ b/Core/MIPS/IR/IRJit.cpp @@ -146,7 +146,7 @@ bool IRJit::CompileBlock(u32 em_address, std::vector &instructions, u32 IRBlock *b = blocks_.GetBlock(block_num); b->SetInstructions(instructions); - b->SetOriginalSize(mipsBytes); + b->SetOriginalAddrSize(em_address, mipsBytes); if (preload) { // Hash, then only update page stats, don't link yet. // TODO: Should we always hash? Then we can reuse blocks. diff --git a/Core/MIPS/IR/IRJit.h b/Core/MIPS/IR/IRJit.h index 734f576066..07523d092a 100644 --- a/Core/MIPS/IR/IRJit.h +++ b/Core/MIPS/IR/IRJit.h @@ -69,7 +69,8 @@ public: bool HasOriginalFirstOp() const; bool RestoreOriginalFirstOp(int number); bool IsValid() const { return origAddr_ != 0 && origFirstOpcode_.encoding != 0x68FFFFFF; } - void SetOriginalSize(u32 size) { + void SetOriginalAddrSize(u32 address, u32 size) { + origAddr_ = address; origSize_ = size; } void SetTargetOffset(int offset) { @@ -114,25 +115,28 @@ public: IRBlockCache() {} void Clear(); std::vector FindInvalidatedBlockNumbers(u32 address, u32 length); - void FinalizeBlock(int i, bool preload = false); + void FinalizeBlock(int blockNum, bool preload = false); int GetNumBlocks() const override { return (int)blocks_.size(); } int AllocateBlock(int emAddr) { blocks_.push_back(IRBlock(emAddr)); return (int)blocks_.size() - 1; } - IRBlock *GetBlock(int i) { - if (i >= 0 && i < (int)blocks_.size()) { - return &blocks_[i]; + IRBlock *GetBlock(int blockNum) { + if (blockNum >= 0 && blockNum < (int)blocks_.size()) { + return &blocks_[blockNum]; } else { return nullptr; } } - IRBlock *GetBlockUnchecked(int i) { - return &blocks_[i]; + bool IsValidBlock(int blockNum) const override { + return blockNum < (int)blocks_.size() && blocks_[blockNum].IsValid(); } - const IRBlock *GetBlock(int i) const { - if (i >= 0 && i < (int)blocks_.size()) { - return &blocks_[i]; + IRBlock *GetBlockUnchecked(int blockNum) { + return &blocks_[blockNum]; + } + const IRBlock *GetBlock(int blockNum) const { + if (blockNum >= 0 && blockNum < (int)blocks_.size()) { + return &blocks_[blockNum]; } else { return nullptr; } diff --git a/Core/MIPS/IR/IRNativeCommon.cpp b/Core/MIPS/IR/IRNativeCommon.cpp index abd76511ec..754435e8c6 100644 --- a/Core/MIPS/IR/IRNativeCommon.cpp +++ b/Core/MIPS/IR/IRNativeCommon.cpp @@ -714,6 +714,10 @@ void IRNativeBlockCacheDebugInterface::Init(const IRNativeBackend *backend) { backend_ = backend; } +bool IRNativeBlockCacheDebugInterface::IsValidBlock(int blockNum) const { + return irBlocks_.IsValidBlock(blockNum); +} + int IRNativeBlockCacheDebugInterface::GetNumBlocks() const { return irBlocks_.GetNumBlocks(); } diff --git a/Core/MIPS/IR/IRNativeCommon.h b/Core/MIPS/IR/IRNativeCommon.h index 4afc503698..eae86ada35 100644 --- a/Core/MIPS/IR/IRNativeCommon.h +++ b/Core/MIPS/IR/IRNativeCommon.h @@ -162,10 +162,11 @@ class IRNativeBlockCacheDebugInterface : public JitBlockCacheDebugInterface { public: IRNativeBlockCacheDebugInterface(const MIPSComp::IRBlockCache &irBlocks); void Init(const IRNativeBackend *backend); - int GetNumBlocks() const; - int GetBlockNumberFromStartAddress(u32 em_address, bool realBlocksOnly = true) const; - JitBlockDebugInfo GetBlockDebugInfo(int blockNum) const; - void ComputeStats(BlockCacheStats &bcStats) const; + int GetNumBlocks() const override; + int GetBlockNumberFromStartAddress(u32 em_address, bool realBlocksOnly = true) const override; + JitBlockDebugInfo GetBlockDebugInfo(int blockNum) const override; + void ComputeStats(BlockCacheStats &bcStats) const override; + bool IsValidBlock(int blockNum) const override; private: void GetBlockCodeRange(int blockNum, int *startOffset, int *size) const; diff --git a/Core/MIPS/JitCommon/JitBlockCache.h b/Core/MIPS/JitCommon/JitBlockCache.h index bcf1f5c083..aa8db04f15 100644 --- a/Core/MIPS/JitCommon/JitBlockCache.h +++ b/Core/MIPS/JitCommon/JitBlockCache.h @@ -109,6 +109,7 @@ public: virtual int GetBlockNumberFromStartAddress(u32 em_address, bool realBlocksOnly = true) const = 0; virtual JitBlockDebugInfo GetBlockDebugInfo(int blockNum) const = 0; virtual void ComputeStats(BlockCacheStats &bcStats) const = 0; + virtual bool IsValidBlock(int blockNum) const = 0; virtual ~JitBlockCacheDebugInterface() {} }; @@ -164,6 +165,7 @@ public: void RestoreSavedEmuHackOps(const std::vector &saved); int GetNumBlocks() const override { return num_blocks_; } + bool IsValidBlock(int blockNum) const override { return blockNum < num_blocks_ && !blocks_[blockNum].invalid; } static int GetBlockExitSize(); diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index f16dbfef01..cad988c032 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -1060,6 +1060,9 @@ void JitCompareScreen::UpdateDisasm() { } JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface(); + if (!blockCacheDebug->IsValidBlock(currentBlock_)) { + return; + } char temp[256]; snprintf(temp, sizeof(temp), "%i/%i", currentBlock_, blockCacheDebug->GetNumBlocks()); @@ -1205,7 +1208,13 @@ UI::EventReturn JitCompareScreen::OnRandomBlock(UI::EventParams &e) { int numBlocks = blockCache->GetNumBlocks(); if (numBlocks > 0) { - currentBlock_ = rand() % numBlocks; + int tries = 100; + while (tries-- > 0) { + currentBlock_ = rand() % numBlocks; + if (blockCache->IsValidBlock(currentBlock_)) { + break; + } + } } UpdateDisasm(); return UI::EVENT_DONE;