diff --git a/Common/CodeBlock.h b/Common/CodeBlock.h index f7fc8a2481..766d0a1cca 100644 --- a/Common/CodeBlock.h +++ b/Common/CodeBlock.h @@ -32,7 +32,7 @@ public: virtual const u8 *GetCodePtr() const = 0; - u8 *GetBasePtr() { + u8 *GetBasePtr() const { return region; } diff --git a/Core/MIPS/IR/IRJit.h b/Core/MIPS/IR/IRJit.h index 35387e7e44..241e43fc41 100644 --- a/Core/MIPS/IR/IRJit.h +++ b/Core/MIPS/IR/IRJit.h @@ -124,6 +124,13 @@ public: return nullptr; } } + const IRBlock *GetBlock(int i) const { + if (i >= 0 && i < (int)blocks_.size()) { + return &blocks_[i]; + } else { + return nullptr; + } + } int FindPreloadBlock(u32 em_address); int FindByCookie(int cookie); @@ -180,7 +187,7 @@ public: void UnlinkBlock(u8 *checkedEntry, u32 originalAddress) override; protected: - virtual bool CompileBlock(u32 em_address, std::vector &instructions, u32 &mipsBytes, bool preload); + bool CompileBlock(u32 em_address, std::vector &instructions, u32 &mipsBytes, bool preload); virtual bool CompileTargetBlock(IRBlock *block, int block_num, bool preload) { return true; } JitOptions jo; diff --git a/Core/MIPS/IR/IRNativeCommon.cpp b/Core/MIPS/IR/IRNativeCommon.cpp index 6bb1c6b2c1..eb56319d75 100644 --- a/Core/MIPS/IR/IRNativeCommon.cpp +++ b/Core/MIPS/IR/IRNativeCommon.cpp @@ -16,12 +16,87 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "Common/Profiler/Profiler.h" +#include "Common/StringUtils.h" +#include "Common/TimeUtil.h" +#include "Core/MIPS/MIPSTables.h" #include "Core/MIPS/IR/IRNativeCommon.h" using namespace MIPSComp; namespace MIPSComp { +// Compile time flag to enable debug stats for not compiled ops. +static constexpr bool enableDebugStats = false; + +// Used only for debugging when enableDebug is true above. +static std::map debugSeenNotCompiledIR; +static std::map debugSeenNotCompiled; +static double lastDebugStatsLog = 0.0; + +static void LogDebugStats() { + if (!enableDebugStats) + return; + + double now = time_now_d(); + if (now < lastDebugStatsLog + 1.0) + return; + lastDebugStatsLog = now; + + int worstIROp = -1; + int worstIRVal = 0; + for (auto it : debugSeenNotCompiledIR) { + if (it.second > worstIRVal) { + worstIRVal = it.second; + worstIROp = it.first; + } + } + debugSeenNotCompiledIR.clear(); + + const char *worstName = nullptr; + int worstVal = 0; + for (auto it : debugSeenNotCompiled) { + if (it.second > worstVal) { + worstVal = it.second; + worstName = it.first; + } + } + debugSeenNotCompiled.clear(); + + if (worstIROp != -1) + WARN_LOG(JIT, "Most not compiled IR op: %s (%d)", GetIRMeta((IROp)worstIROp)->name, worstIRVal); + if (worstName != nullptr) + WARN_LOG(JIT, "Most not compiled op: %s (%d)", worstName, worstVal); +} + +bool IRNativeBackend::DebugStatsEnabled() const { + return enableDebugStats; +} + +void IRNativeBackend::NotifyMIPSInterpret(const char *name) { + _assert_(enableDebugStats); + debugSeenNotCompiled[name]++; +} + +void IRNativeBackend::DoMIPSInst(uint32_t value) { + MIPSOpcode op; + memcpy(&op, &value, sizeof(op)); + + if constexpr (enableDebugStats) + debugSeenNotCompiled[MIPSGetName(op)]++; + + MIPSInterpret(op); +} + +uint32_t IRNativeBackend::DoIRInst(uint64_t value) { + IRInst inst; + memcpy(&inst, &value, sizeof(inst)); + + if constexpr (enableDebugStats) + debugSeenNotCompiledIR[(uint8_t)inst.op]++; + + return IRInterpret(currentMIPS, &inst, 1); +} + void IRNativeBackend::CompileIRInst(IRInst inst) { switch (inst.op) { case IROp::Nop: @@ -312,10 +387,127 @@ void IRNativeBackend::CompileIRInst(IRInst inst) { } } +IRNativeJit::IRNativeJit(MIPSState *mipsState) + : IRJit(mipsState), debugInterface_(blocks_) {} + +void IRNativeJit::Init(IRNativeBackend &backend) { + backend_ = &backend; + debugInterface_.Init(&backend_->CodeBlock()); + backend_->GenerateFixedCode(); + + // Wanted this to be a reference, but vtbls get in the way. Shouldn't change. + hooks_ = backend.GetNativeHooks(); +} + +bool IRNativeJit::CompileTargetBlock(IRBlock *block, int block_num, bool preload) { + return backend_->CompileBlock(block, block_num, preload); +} + +void IRNativeJit::RunLoopUntil(u64 globalticks) { + if constexpr (enableDebugStats) { + LogDebugStats(); + } + + PROFILE_THIS_SCOPE("jit"); + hooks_.enterDispatcher(); +} + +void IRNativeJit::ClearCache() { + IRJit::ClearCache(); + backend_->ClearAllBlocks(); +} + +bool IRNativeJit::DescribeCodePtr(const u8 *ptr, std::string &name) { + if (ptr != nullptr && backend_->DescribeCodePtr(ptr, name)) + return true; + + int offset = backend_->OffsetFromCodePtr(ptr); + if (offset == -1) + return false; + + int block_num = -1; + for (int i = 0; i < blocks_.GetNumBlocks(); ++i) { + const auto &b = blocks_.GetBlock(i); + // We allocate linearly. + if (b->GetTargetOffset() <= offset) + block_num = i; + if (b->GetTargetOffset() > offset) + break; + } + + if (block_num == -1) { + name = "(unknown or deleted block)"; + return true; + } + + const IRBlock *block = blocks_.GetBlock(block_num); + if (block) { + u32 start = 0, size = 0; + block->GetRange(start, size); + name = StringFromFormat("(block %d at %08x)", block_num, start); + return true; + } + return false; +} + +bool IRNativeJit::CodeInRange(const u8 *ptr) const { + return backend_->CodeInRange(ptr); +} + +bool IRNativeJit::IsAtDispatchFetch(const u8 *ptr) const { + return ptr == backend_->GetNativeHooks().dispatchFetch; +} + +const u8 *IRNativeJit::GetDispatcher() const { + return backend_->GetNativeHooks().dispatcher; +} + +const u8 *IRNativeJit::GetCrashHandler() const { + return backend_->GetNativeHooks().crashHandler; +} + +JitBlockCacheDebugInterface *IRNativeJit::GetBlockCacheDebugInterface() { + return &debugInterface_; +} + +bool IRNativeBackend::CodeInRange(const u8 *ptr) const { + return CodeBlock().IsInSpace(ptr); +} + +bool IRNativeBackend::DescribeCodePtr(const u8 *ptr, std::string &name) const { + if (!CodeBlock().IsInSpace(ptr)) + return false; + + // Used in disassembly viewer. + if (ptr == (const uint8_t *)hooks_.enterDispatcher) { + name = "enterDispatcher"; + } else if (ptr == hooks_.dispatcher) { + name = "dispatcher"; + } else if (ptr == hooks_.dispatchFetch) { + name = "dispatchFetch"; + } else if (ptr == hooks_.crashHandler) { + name = "crashHandler"; + } else { + return false; + } + return true; +} + +int IRNativeBackend::OffsetFromCodePtr(const u8 *ptr) { + auto &codeBlock = CodeBlock(); + if (!codeBlock.IsInSpace(ptr)) + return -1; + return (int)codeBlock.GetOffset(ptr); +} + } // namespace MIPSComp -IRNativeBlockCacheDebugInterface::IRNativeBlockCacheDebugInterface(IRBlockCache &irBlocks, CodeBlockCommon &codeBlock) - : irBlocks_(irBlocks), codeBlock_(codeBlock) {} +IRNativeBlockCacheDebugInterface::IRNativeBlockCacheDebugInterface(const IRBlockCache &irBlocks) + : irBlocks_(irBlocks) {} + +void IRNativeBlockCacheDebugInterface::Init(const CodeBlockCommon *codeBlock) { + codeBlock_ = codeBlock; +} int IRNativeBlockCacheDebugInterface::GetNumBlocks() const { return irBlocks_.GetNumBlocks(); @@ -331,7 +523,7 @@ void IRNativeBlockCacheDebugInterface::GetBlockCodeRange(int blockNum, int *star // We assume linear allocation. Maybe a bit dangerous, should always be right. if (blockNum + 1 >= GetNumBlocks()) { // Last block, get from current code pointer. - endOffset = (int)codeBlock_.GetOffset(codeBlock_.GetCodePtr()); + endOffset = (int)codeBlock_->GetOffset(codeBlock_->GetCodePtr()); } else { endOffset = irBlocks_.GetBlock(blockNum + 1)->GetTargetOffset(); _assert_msg_(endOffset >= blockOffset, "Next block not sequential, block=%d/%08x, next=%d/%08x", blockNum, blockOffset, blockNum + 1, endOffset); @@ -348,7 +540,7 @@ JitBlockDebugInfo IRNativeBlockCacheDebugInterface::GetBlockDebugInfo(int blockN GetBlockCodeRange(blockNum, &blockOffset, &codeSize); // TODO: Normal entry? - const u8 *blockStart = codeBlock_.GetBasePtr() + blockOffset; + const u8 *blockStart = codeBlock_->GetBasePtr() + blockOffset; #if PPSSPP_ARCH(ARM) debugInfo.targetDisasm = DisassembleArm2(blockStart, codeSize); #elif PPSSPP_ARCH(ARM64) diff --git a/Core/MIPS/IR/IRNativeCommon.h b/Core/MIPS/IR/IRNativeCommon.h index b0737a7319..b9678dd12f 100644 --- a/Core/MIPS/IR/IRNativeCommon.h +++ b/Core/MIPS/IR/IRNativeCommon.h @@ -20,7 +20,8 @@ class IRNativeBlockCacheDebugInterface : public JitBlockCacheDebugInterface { public: - IRNativeBlockCacheDebugInterface(MIPSComp::IRBlockCache &irBlocks, CodeBlockCommon &codeBlock); + IRNativeBlockCacheDebugInterface(const MIPSComp::IRBlockCache &irBlocks); + void Init(const CodeBlockCommon *codeBlock); int GetNumBlocks() const; int GetBlockNumberFromStartAddress(u32 em_address, bool realBlocksOnly = true) const; JitBlockDebugInfo GetBlockDebugInfo(int blockNum) const; @@ -29,18 +30,42 @@ public: private: void GetBlockCodeRange(int blockNum, int *startOffset, int *size) const; - MIPSComp::IRBlockCache &irBlocks_; - CodeBlockCommon &codeBlock_; + const MIPSComp::IRBlockCache &irBlocks_; + const CodeBlockCommon *codeBlock_ = nullptr; }; namespace MIPSComp { +typedef void (*IRNativeFuncNoArg)(); + +struct IRNativeHooks { + IRNativeFuncNoArg enterDispatcher = nullptr; + + const uint8_t *dispatcher = nullptr; + const uint8_t *dispatchFetch = nullptr; + const uint8_t *crashHandler = nullptr; +}; + class IRNativeBackend { public: virtual ~IRNativeBackend() {} void CompileIRInst(IRInst inst); + virtual bool DescribeCodePtr(const u8 *ptr, std::string &name) const; + bool CodeInRange(const u8 *ptr) const; + int OffsetFromCodePtr(const u8 *ptr); + + virtual void GenerateFixedCode() = 0; + virtual bool CompileBlock(IRBlock *block, int block_num, bool preload) = 0; + virtual void ClearAllBlocks() = 0; + + const IRNativeHooks &GetNativeHooks() const { + return hooks_; + } + + virtual const CodeBlockCommon &CodeBlock() const = 0; + protected: virtual void CompIR_Arith(IRInst inst) = 0; virtual void CompIR_Assign(IRInst inst) = 0; @@ -84,11 +109,46 @@ protected: virtual void CompIR_VecPack(IRInst inst) = 0; virtual void CompIR_VecStore(IRInst inst) = 0; virtual void CompIR_ValidateAddress(IRInst inst) = 0; + + // Returns true when debugging statistics should be compiled in. + bool DebugStatsEnabled() const; + + // Callback (compile when DebugStatsEnabled()) to log a base interpreter hit. + // Call the func returned by MIPSGetInterpretFunc(op) directly for interpret. + static void NotifyMIPSInterpret(const char *name); + + // Callback to log AND perform a base interpreter op. Alternative to NotifyMIPSInterpret(). + static void DoMIPSInst(uint32_t op); + + // Callback to log AND perform an IR interpreter inst. Returns 0 or a PC to jump to. + static uint32_t DoIRInst(uint64_t inst); + + IRNativeHooks hooks_; }; class IRNativeJit : public IRJit { public: - IRNativeJit(MIPSState *mipsState) : IRJit(mipsState) {} + IRNativeJit(MIPSState *mipsState); + + void RunLoopUntil(u64 globalticks) override; + + void ClearCache() override; + + bool DescribeCodePtr(const u8 *ptr, std::string &name) override; + bool CodeInRange(const u8 *ptr) const override; + bool IsAtDispatchFetch(const u8 *ptr) const override; + const u8 *GetDispatcher() const override; + const u8 *GetCrashHandler() const override; + + JitBlockCacheDebugInterface *GetBlockCacheDebugInterface() override; + +protected: + void Init(IRNativeBackend &backend); + bool CompileTargetBlock(IRBlock *block, int block_num, bool preload) override; + + IRNativeBackend *backend_ = nullptr; + IRNativeHooks hooks_; + IRNativeBlockCacheDebugInterface debugInterface_; }; } // namespace MIPSComp diff --git a/Core/MIPS/RiscV/RiscVAsm.cpp b/Core/MIPS/RiscV/RiscVAsm.cpp index e07b59760b..b38aba928e 100644 --- a/Core/MIPS/RiscV/RiscVAsm.cpp +++ b/Core/MIPS/RiscV/RiscVAsm.cpp @@ -44,17 +44,7 @@ static void ShowPC(u32 downcount, void *membase, void *jitbase) { count++; } -static void ShowBlockError(int type) { - if (type == 1) { - ERROR_LOG(JIT, "[%08x] ShowBlockError: block num was out of range in emuhack", currentMIPS->pc); - } else if (type == 2) { - ERROR_LOG(JIT, "[%08x] ShowBlockError: block num pointed to null jitblock", currentMIPS->pc); - } else { - ERROR_LOG(JIT, "[%08x] ShowBlockError: invalid error type", currentMIPS->pc); - } -} - -void RiscVJit::GenerateFixedCode(const JitOptions &jo) { +void RiscVJitBackend::GenerateFixedCode() { BeginWrite(GetMemoryProtectPageSize()); const u8 *start = AlignCodePage(); @@ -104,7 +94,7 @@ void RiscVJit::GenerateFixedCode(const JitOptions &jo) { RET(); } - enterDispatcher_ = AlignCode16(); + hooks_.enterDispatcher = (IRNativeFuncNoArg)AlignCode16(); // Start by saving some regs on the stack. There are 12 GPs and 12 FPs we want. // Note: we leave R_SP as, well, SP, so it doesn't need to be saved. @@ -157,7 +147,7 @@ void RiscVJit::GenerateFixedCode(const JitOptions &jo) { dispatcherPCInSCRATCH1_ = GetCodePtr(); MovToPC(SCRATCH1); - dispatcher_ = GetCodePtr(); + hooks_.dispatcher = GetCodePtr(); FixupBranch bail = BLT(DOWNCOUNTREG, R_ZERO); SetJumpTarget(skipToRealDispatch); @@ -177,7 +167,7 @@ void RiscVJit::GenerateFixedCode(const JitOptions &jo) { AND(SCRATCH1, SCRATCH1, SCRATCH2); #endif ADD(SCRATCH1, SCRATCH1, MEMBASEREG); - dispatcherFetch_ = GetCodePtr(); + hooks_.dispatchFetch = GetCodePtr(); LWU(SCRATCH1, SCRATCH1, 0); SRLI(SCRATCH2, SCRATCH1, 24); // We're in other words comparing to the top 8 bits of MIPS_EMUHACK_OPCODE by subtracting. @@ -224,7 +214,7 @@ void RiscVJit::GenerateFixedCode(const JitOptions &jo) { RET(); - crashHandler_ = GetCodePtr(); + hooks_.crashHandler = GetCodePtr(); LI(SCRATCH1, &coreState, SCRATCH2); LI(SCRATCH2, CORE_RUNTIME_ERROR); SW(SCRATCH2, SCRATCH1, 0); diff --git a/Core/MIPS/RiscV/RiscVCompALU.cpp b/Core/MIPS/RiscV/RiscVCompALU.cpp index 5cb2ff256c..e2f28683dc 100644 --- a/Core/MIPS/RiscV/RiscVCompALU.cpp +++ b/Core/MIPS/RiscV/RiscVCompALU.cpp @@ -35,7 +35,7 @@ namespace MIPSComp { using namespace RiscVGen; using namespace RiscVJitConstants; -void RiscVJit::CompIR_Arith(IRInst inst) { +void RiscVJitBackend::CompIR_Arith(IRInst inst) { CONDITIONAL_DISABLE; bool allowPtrMath = true; @@ -96,7 +96,7 @@ void RiscVJit::CompIR_Arith(IRInst inst) { } } -void RiscVJit::CompIR_Logic(IRInst inst) { +void RiscVJitBackend::CompIR_Logic(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { @@ -187,7 +187,7 @@ void RiscVJit::CompIR_Logic(IRInst inst) { } } -void RiscVJit::CompIR_Assign(IRInst inst) { +void RiscVJitBackend::CompIR_Assign(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { @@ -227,7 +227,7 @@ void RiscVJit::CompIR_Assign(IRInst inst) { } } -void RiscVJit::CompIR_Bits(IRInst inst) { +void RiscVJitBackend::CompIR_Bits(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { @@ -269,7 +269,7 @@ void RiscVJit::CompIR_Bits(IRInst inst) { } } -void RiscVJit::CompIR_Shift(IRInst inst) { +void RiscVJitBackend::CompIR_Shift(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { @@ -367,7 +367,7 @@ void RiscVJit::CompIR_Shift(IRInst inst) { } } -void RiscVJit::CompIR_Compare(IRInst inst) { +void RiscVJitBackend::CompIR_Compare(IRInst inst) { CONDITIONAL_DISABLE; RiscVReg lhs = INVALID_REG; @@ -445,7 +445,7 @@ void RiscVJit::CompIR_Compare(IRInst inst) { } } -void RiscVJit::CompIR_CondAssign(IRInst inst) { +void RiscVJitBackend::CompIR_CondAssign(IRInst inst) { CONDITIONAL_DISABLE; RiscVReg lhs = INVALID_REG; @@ -519,7 +519,7 @@ void RiscVJit::CompIR_CondAssign(IRInst inst) { } } -void RiscVJit::CompIR_HiLo(IRInst inst) { +void RiscVJitBackend::CompIR_HiLo(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { @@ -553,7 +553,7 @@ void RiscVJit::CompIR_HiLo(IRInst inst) { } } -void RiscVJit::CompIR_Mult(IRInst inst) { +void RiscVJitBackend::CompIR_Mult(IRInst inst) { CONDITIONAL_DISABLE; auto makeArgsUnsigned = [&](RiscVReg *lhs, RiscVReg *rhs) { @@ -652,7 +652,7 @@ void RiscVJit::CompIR_Mult(IRInst inst) { } } -void RiscVJit::CompIR_Div(IRInst inst) { +void RiscVJitBackend::CompIR_Div(IRInst inst) { CONDITIONAL_DISABLE; RiscVReg numReg, denomReg; diff --git a/Core/MIPS/RiscV/RiscVCompBranch.cpp b/Core/MIPS/RiscV/RiscVCompBranch.cpp index aa9d2467a0..121b3fa789 100644 --- a/Core/MIPS/RiscV/RiscVCompBranch.cpp +++ b/Core/MIPS/RiscV/RiscVCompBranch.cpp @@ -34,7 +34,7 @@ namespace MIPSComp { using namespace RiscVGen; using namespace RiscVJitConstants; -void RiscVJit::CompIR_Exit(IRInst inst) { +void RiscVJitBackend::CompIR_Exit(IRInst inst) { CONDITIONAL_DISABLE; RiscVReg exitReg = INVALID_REG; @@ -64,7 +64,7 @@ void RiscVJit::CompIR_Exit(IRInst inst) { } } -void RiscVJit::CompIR_ExitIf(IRInst inst) { +void RiscVJitBackend::CompIR_ExitIf(IRInst inst) { CONDITIONAL_DISABLE; RiscVReg lhs = INVALID_REG; diff --git a/Core/MIPS/RiscV/RiscVCompFPU.cpp b/Core/MIPS/RiscV/RiscVCompFPU.cpp index 18cd1a00c2..9dd2ea6958 100644 --- a/Core/MIPS/RiscV/RiscVCompFPU.cpp +++ b/Core/MIPS/RiscV/RiscVCompFPU.cpp @@ -34,7 +34,7 @@ namespace MIPSComp { using namespace RiscVGen; using namespace RiscVJitConstants; -void RiscVJit::CompIR_FArith(IRInst inst) { +void RiscVJitBackend::CompIR_FArith(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { @@ -108,7 +108,7 @@ void RiscVJit::CompIR_FArith(IRInst inst) { } } -void RiscVJit::CompIR_FCondAssign(IRInst inst) { +void RiscVJitBackend::CompIR_FCondAssign(IRInst inst) { CONDITIONAL_DISABLE; if (inst.op != IROp::FMin && inst.op != IROp::FMax) INVALIDOP; @@ -174,7 +174,7 @@ void RiscVJit::CompIR_FCondAssign(IRInst inst) { SetJumpTarget(finish); } -void RiscVJit::CompIR_FAssign(IRInst inst) { +void RiscVJitBackend::CompIR_FAssign(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { @@ -220,7 +220,7 @@ void RiscVJit::CompIR_FAssign(IRInst inst) { } } -void RiscVJit::CompIR_FRound(IRInst inst) { +void RiscVJitBackend::CompIR_FRound(IRInst inst) { CONDITIONAL_DISABLE; // TODO: If this is followed by a GPR transfer, might want to combine. @@ -251,7 +251,7 @@ void RiscVJit::CompIR_FRound(IRInst inst) { FMV(FMv::W, FMv::X, fpr.R(inst.dest), SCRATCH1); } -void RiscVJit::CompIR_FCvt(IRInst inst) { +void RiscVJitBackend::CompIR_FCvt(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { @@ -274,7 +274,7 @@ void RiscVJit::CompIR_FCvt(IRInst inst) { } } -void RiscVJit::CompIR_FSat(IRInst inst) { +void RiscVJitBackend::CompIR_FSat(IRInst inst) { CONDITIONAL_DISABLE; RiscVReg tempReg = INVALID_REG; @@ -334,7 +334,7 @@ void RiscVJit::CompIR_FSat(IRInst inst) { } } -void RiscVJit::CompIR_FCompare(IRInst inst) { +void RiscVJitBackend::CompIR_FCompare(IRInst inst) { CONDITIONAL_DISABLE; constexpr IRRegIndex IRREG_VFPUL_CC = IRREG_VFPU_CTRL_BASE + VFPU_CTRL_CC; @@ -548,7 +548,7 @@ void RiscVJit::CompIR_FCompare(IRInst inst) { } } -void RiscVJit::CompIR_RoundingMode(IRInst inst) { +void RiscVJitBackend::CompIR_RoundingMode(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { @@ -570,7 +570,7 @@ void RiscVJit::CompIR_RoundingMode(IRInst inst) { } } -void RiscVJit::CompIR_FSpecial(IRInst inst) { +void RiscVJitBackend::CompIR_FSpecial(IRInst inst) { CONDITIONAL_DISABLE; #ifdef __riscv_float_abi_soft diff --git a/Core/MIPS/RiscV/RiscVCompLoadStore.cpp b/Core/MIPS/RiscV/RiscVCompLoadStore.cpp index d6a49e6f13..0713016d6c 100644 --- a/Core/MIPS/RiscV/RiscVCompLoadStore.cpp +++ b/Core/MIPS/RiscV/RiscVCompLoadStore.cpp @@ -34,7 +34,7 @@ namespace MIPSComp { using namespace RiscVGen; using namespace RiscVJitConstants; -void RiscVJit::SetScratch1ToSrc1Address(IRReg src1) { +void RiscVJitBackend::SetScratch1ToSrc1Address(IRReg src1) { gpr.MapReg(src1); #ifdef MASKED_PSP_MEMORY SLLIW(SCRATCH1, gpr.R(src1), 2); @@ -53,7 +53,7 @@ void RiscVJit::SetScratch1ToSrc1Address(IRReg src1) { #endif } -int32_t RiscVJit::AdjustForAddressOffset(RiscVGen::RiscVReg *reg, int32_t constant, int32_t range) { +int32_t RiscVJitBackend::AdjustForAddressOffset(RiscVGen::RiscVReg *reg, int32_t constant, int32_t range) { if (constant < -2048 || constant + range > 2047) { LI(SCRATCH2, constant); ADD(SCRATCH1, *reg, SCRATCH2); @@ -63,7 +63,7 @@ int32_t RiscVJit::AdjustForAddressOffset(RiscVGen::RiscVReg *reg, int32_t consta return constant; } -void RiscVJit::CompIR_Load(IRInst inst) { +void RiscVJitBackend::CompIR_Load(IRInst inst) { CONDITIONAL_DISABLE; gpr.SpillLock(inst.dest, inst.src1); @@ -124,7 +124,7 @@ void RiscVJit::CompIR_Load(IRInst inst) { } } -void RiscVJit::CompIR_LoadShift(IRInst inst) { +void RiscVJitBackend::CompIR_LoadShift(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { @@ -140,7 +140,7 @@ void RiscVJit::CompIR_LoadShift(IRInst inst) { } } -void RiscVJit::CompIR_FLoad(IRInst inst) { +void RiscVJitBackend::CompIR_FLoad(IRInst inst) { CONDITIONAL_DISABLE; RiscVReg addrReg = INVALID_REG; @@ -173,7 +173,7 @@ void RiscVJit::CompIR_FLoad(IRInst inst) { } } -void RiscVJit::CompIR_VecLoad(IRInst inst) { +void RiscVJitBackend::CompIR_VecLoad(IRInst inst) { CONDITIONAL_DISABLE; RiscVReg addrReg = INVALID_REG; @@ -210,7 +210,7 @@ void RiscVJit::CompIR_VecLoad(IRInst inst) { } } -void RiscVJit::CompIR_Store(IRInst inst) { +void RiscVJitBackend::CompIR_Store(IRInst inst) { CONDITIONAL_DISABLE; gpr.SpillLock(inst.src3, inst.src1); @@ -255,7 +255,7 @@ void RiscVJit::CompIR_Store(IRInst inst) { } } -void RiscVJit::CompIR_CondStore(IRInst inst) { +void RiscVJitBackend::CompIR_CondStore(IRInst inst) { CONDITIONAL_DISABLE; if (inst.op != IROp::Store32Conditional) INVALIDOP; @@ -297,7 +297,7 @@ void RiscVJit::CompIR_CondStore(IRInst inst) { } } -void RiscVJit::CompIR_StoreShift(IRInst inst) { +void RiscVJitBackend::CompIR_StoreShift(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { @@ -313,7 +313,7 @@ void RiscVJit::CompIR_StoreShift(IRInst inst) { } } -void RiscVJit::CompIR_FStore(IRInst inst) { +void RiscVJitBackend::CompIR_FStore(IRInst inst) { CONDITIONAL_DISABLE; RiscVReg addrReg = INVALID_REG; @@ -346,7 +346,7 @@ void RiscVJit::CompIR_FStore(IRInst inst) { } } -void RiscVJit::CompIR_VecStore(IRInst inst) { +void RiscVJitBackend::CompIR_VecStore(IRInst inst) { CONDITIONAL_DISABLE; RiscVReg addrReg = INVALID_REG; diff --git a/Core/MIPS/RiscV/RiscVCompSystem.cpp b/Core/MIPS/RiscV/RiscVCompSystem.cpp index 727465fad0..ec519e66fd 100644 --- a/Core/MIPS/RiscV/RiscVCompSystem.cpp +++ b/Core/MIPS/RiscV/RiscVCompSystem.cpp @@ -38,7 +38,7 @@ namespace MIPSComp { using namespace RiscVGen; using namespace RiscVJitConstants; -void RiscVJit::CompIR_Basic(IRInst inst) { +void RiscVJitBackend::CompIR_Basic(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { @@ -85,7 +85,7 @@ void RiscVJit::CompIR_Basic(IRInst inst) { } } -void RiscVJit::CompIR_Transfer(IRInst inst) { +void RiscVJitBackend::CompIR_Transfer(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { @@ -177,7 +177,7 @@ void RiscVJit::CompIR_Transfer(IRInst inst) { } } -void RiscVJit::CompIR_System(IRInst inst) { +void RiscVJitBackend::CompIR_System(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { @@ -236,7 +236,7 @@ void RiscVJit::CompIR_System(IRInst inst) { } } -void RiscVJit::CompIR_Breakpoint(IRInst inst) { +void RiscVJitBackend::CompIR_Breakpoint(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { @@ -251,7 +251,7 @@ void RiscVJit::CompIR_Breakpoint(IRInst inst) { } } -void RiscVJit::CompIR_ValidateAddress(IRInst inst) { +void RiscVJitBackend::CompIR_ValidateAddress(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { diff --git a/Core/MIPS/RiscV/RiscVCompVec.cpp b/Core/MIPS/RiscV/RiscVCompVec.cpp index 8140f2b856..08739152ae 100644 --- a/Core/MIPS/RiscV/RiscVCompVec.cpp +++ b/Core/MIPS/RiscV/RiscVCompVec.cpp @@ -34,7 +34,7 @@ namespace MIPSComp { using namespace RiscVGen; using namespace RiscVJitConstants; -void RiscVJit::CompIR_VecAssign(IRInst inst) { +void RiscVJitBackend::CompIR_VecAssign(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { @@ -129,7 +129,7 @@ void RiscVJit::CompIR_VecAssign(IRInst inst) { } } -void RiscVJit::CompIR_VecArith(IRInst inst) { +void RiscVJitBackend::CompIR_VecArith(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { @@ -184,7 +184,7 @@ void RiscVJit::CompIR_VecArith(IRInst inst) { } } -void RiscVJit::CompIR_VecHoriz(IRInst inst) { +void RiscVJitBackend::CompIR_VecHoriz(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { @@ -230,7 +230,7 @@ void RiscVJit::CompIR_VecHoriz(IRInst inst) { } } -void RiscVJit::CompIR_VecPack(IRInst inst) { +void RiscVJitBackend::CompIR_VecPack(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { @@ -266,7 +266,7 @@ void RiscVJit::CompIR_VecPack(IRInst inst) { } } -void RiscVJit::CompIR_VecClamp(IRInst inst) { +void RiscVJitBackend::CompIR_VecClamp(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { diff --git a/Core/MIPS/RiscV/RiscVJit.cpp b/Core/MIPS/RiscV/RiscVJit.cpp index 477c455f87..983e104e6c 100644 --- a/Core/MIPS/RiscV/RiscVJit.cpp +++ b/Core/MIPS/RiscV/RiscVJit.cpp @@ -15,62 +15,18 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "Common/StringUtils.h" -#include "Common/TimeUtil.h" #include "Core/MemMap.h" #include "Core/MIPS/MIPSTables.h" #include "Core/MIPS/RiscV/RiscVJit.h" #include "Core/MIPS/RiscV/RiscVRegCache.h" -#include "Common/Profiler/Profiler.h" namespace MIPSComp { using namespace RiscVGen; using namespace RiscVJitConstants; -static constexpr bool enableDebug = false; - -static std::map debugSeenNotCompiledIR; -static std::map debugSeenNotCompiled; -double lastDebugLog = 0.0; - -static void LogDebugNotCompiled() { - if (!enableDebug) - return; - - double now = time_now_d(); - if (now < lastDebugLog + 1.0) - return; - lastDebugLog = now; - - int worstIROp = -1; - int worstIRVal = 0; - for (auto it : debugSeenNotCompiledIR) { - if (it.second > worstIRVal) { - worstIRVal = it.second; - worstIROp = it.first; - } - } - debugSeenNotCompiledIR.clear(); - - const char *worstName = nullptr; - int worstVal = 0; - for (auto it : debugSeenNotCompiled) { - if (it.second > worstVal) { - worstVal = it.second; - worstName = it.first; - } - } - debugSeenNotCompiled.clear(); - - if (worstIROp != -1) - WARN_LOG(JIT, "Most not compiled IR op: %s (%d)", GetIRMeta((IROp)worstIROp)->name, worstIRVal); - if (worstName != nullptr) - WARN_LOG(JIT, "Most not compiled op: %s (%d)", worstName, worstVal); -} - -RiscVJit::RiscVJit(MIPSState *mipsState) - : IRNativeJit(mipsState), gpr(mipsState, &jo), fpr(mipsState, &jo), debugInterface_(blocks_, *this) { +RiscVJitBackend::RiscVJitBackend(MIPSState *mipsState, JitOptions &jitopt) + : mips_(mipsState), jo(jitopt), gpr(mipsState, &jo), fpr(mipsState, &jo) { // Automatically disable incompatible options. if (((intptr_t)Memory::base & 0x00000000FFFFFFFFUL) != 0) { jo.enablePointerify = false; @@ -83,31 +39,16 @@ RiscVJit::RiscVJit(MIPSState *mipsState) gpr.Init(this); fpr.Init(this); - - GenerateFixedCode(jo); } -RiscVJit::~RiscVJit() { -} - -void RiscVJit::RunLoopUntil(u64 globalticks) { - if constexpr (enableDebug) { - LogDebugNotCompiled(); - } - - PROFILE_THIS_SCOPE("jit"); - ((void (*)())enterDispatcher_)(); -} - -JitBlockCacheDebugInterface *MIPSComp::RiscVJit::GetBlockCacheDebugInterface() { - return &debugInterface_; +RiscVJitBackend::~RiscVJitBackend() { } static void NoBlockExits() { _assert_msg_(false, "Never exited block, invalid IR?"); } -bool RiscVJit::CompileTargetBlock(IRBlock *block, int block_num, bool preload) { +bool RiscVJitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) { if (GetSpaceLeft() < 0x800) return false; @@ -138,9 +79,10 @@ bool RiscVJit::CompileTargetBlock(IRBlock *block, int block_num, bool preload) { } // We should've written an exit above. If we didn't, bad things will happen. - if (enableDebug) { + // Only check if debug stats are enabled - needlessly wastes jit space. + if (DebugStatsEnabled()) { QuickCallFunction(&NoBlockExits); - QuickJ(R_RA, crashHandler_); + QuickJ(R_RA, hooks_.crashHandler); } FlushIcache(); @@ -148,17 +90,7 @@ bool RiscVJit::CompileTargetBlock(IRBlock *block, int block_num, bool preload) { return true; } -static u32 DoIRInst(uint64_t value) { - IRInst inst; - memcpy(&inst, &value, sizeof(inst)); - - if constexpr (enableDebug) - debugSeenNotCompiledIR[(uint8_t)inst.op]++; - - return IRInterpret(currentMIPS, &inst, 1); -} - -void RiscVJit::CompIR_Generic(IRInst inst) { +void RiscVJitBackend::CompIR_Generic(IRInst inst) { // If we got here, we're going the slow way. uint64_t value; memcpy(&value, &inst, sizeof(inst)); @@ -183,36 +115,29 @@ void RiscVJit::CompIR_Generic(IRInst inst) { } } -static void DebugInterpretHit(const char *name) { - if (enableDebug) - debugSeenNotCompiled[name]++; -} - -void RiscVJit::CompIR_Interpret(IRInst inst) { +void RiscVJitBackend::CompIR_Interpret(IRInst inst) { MIPSOpcode op(inst.constant); // IR protects us against this being a branching instruction (well, hopefully.) FlushAll(); SaveStaticRegisters(); - if (enableDebug) { + if (DebugStatsEnabled()) { LI(X10, MIPSGetName(op)); - QuickCallFunction(&DebugInterpretHit); + QuickCallFunction(&NotifyMIPSInterpret); } LI(X10, (int32_t)inst.constant); QuickCallFunction((const u8 *)MIPSGetInterpretFunc(op)); LoadStaticRegisters(); } -void RiscVJit::FlushAll() { +void RiscVJitBackend::FlushAll() { gpr.FlushAll(); fpr.FlushAll(); } -bool RiscVJit::DescribeCodePtr(const u8 *ptr, std::string &name) { +bool RiscVJitBackend::DescribeCodePtr(const u8 *ptr, std::string &name) const { // Used in disassembly viewer. - if (ptr == dispatcher_) { - name = "dispatcher"; - } else if (ptr == dispatcherPCInSCRATCH1_) { + if (ptr == dispatcherPCInSCRATCH1_) { name = "dispatcher (PC in SCRATCH1)"; } else if (ptr == dispatcherNoCheck_) { name = "dispatcherNoCheck"; @@ -220,81 +145,36 @@ bool RiscVJit::DescribeCodePtr(const u8 *ptr, std::string &name) { name = "saveStaticRegisters"; } else if (ptr == loadStaticRegisters_) { name = "loadStaticRegisters"; - } else if (ptr == enterDispatcher_) { - name = "enterDispatcher"; } else if (ptr == applyRoundingMode_) { name = "applyRoundingMode"; - } else if (!IsInSpace(ptr)) { - return false; } else { - int offset = (int)GetOffset(ptr); - int block_num = -1; - for (int i = 0; i < blocks_.GetNumBlocks(); ++i) { - const auto &b = blocks_.GetBlock(i); - // We allocate linearly. - if (b->GetTargetOffset() <= offset) - block_num = i; - if (b->GetTargetOffset() > offset) - break; - } - - if (block_num == -1) { - name = "(unknown or deleted block)"; - return true; - } - - const IRBlock *block = blocks_.GetBlock(block_num); - if (block) { - u32 start = 0, size = 0; - block->GetRange(start, size); - name = StringFromFormat("(block %d at %08x)", block_num, start); - return true; - } - return false; + return IRNativeBackend::DescribeCodePtr(ptr, name); } return true; } -bool RiscVJit::CodeInRange(const u8 *ptr) const { - return IsInSpace(ptr); -} - -bool RiscVJit::IsAtDispatchFetch(const u8 *ptr) const { - return ptr == dispatcherFetch_; -} - -const u8 *RiscVJit::GetDispatcher() const { - return dispatcher_; -} - -const u8 *RiscVJit::GetCrashHandler() const { - return crashHandler_; -} - -void RiscVJit::ClearCache() { - IRNativeJit::ClearCache(); - +void RiscVJitBackend::ClearAllBlocks() { ClearCodeSpace(jitStartOffset_); FlushIcacheSection(region + jitStartOffset_, region + region_size - jitStartOffset_); } -void RiscVJit::RestoreRoundingMode(bool force) { +void RiscVJitBackend::RestoreRoundingMode(bool force) { FSRMI(Round::NEAREST_EVEN); } -void RiscVJit::ApplyRoundingMode(bool force) { +void RiscVJitBackend::ApplyRoundingMode(bool force) { QuickCallFunction(applyRoundingMode_); } -void RiscVJit::MovFromPC(RiscVReg r) { +void RiscVJitBackend::MovFromPC(RiscVReg r) { LWU(r, CTXREG, offsetof(MIPSState, pc)); } -void RiscVJit::MovToPC(RiscVReg r) { +void RiscVJitBackend::MovToPC(RiscVReg r) { SW(r, CTXREG, offsetof(MIPSState, pc)); } -void RiscVJit::SaveStaticRegisters() { +void RiscVJitBackend::SaveStaticRegisters() { if (jo.useStaticAlloc) { QuickCallFunction(saveStaticRegisters_); } else { @@ -303,7 +183,7 @@ void RiscVJit::SaveStaticRegisters() { } } -void RiscVJit::LoadStaticRegisters() { +void RiscVJitBackend::LoadStaticRegisters() { if (jo.useStaticAlloc) { QuickCallFunction(loadStaticRegisters_); } else { @@ -311,16 +191,16 @@ void RiscVJit::LoadStaticRegisters() { } } -void RiscVJit::NormalizeSrc1(IRInst inst, RiscVReg *reg, RiscVReg tempReg, bool allowOverlap) { +void RiscVJitBackend::NormalizeSrc1(IRInst inst, RiscVReg *reg, RiscVReg tempReg, bool allowOverlap) { *reg = NormalizeR(inst.src1, allowOverlap ? 0 : inst.dest, tempReg); } -void RiscVJit::NormalizeSrc12(IRInst inst, RiscVReg *lhs, RiscVReg *rhs, RiscVReg lhsTempReg, RiscVReg rhsTempReg, bool allowOverlap) { +void RiscVJitBackend::NormalizeSrc12(IRInst inst, RiscVReg *lhs, RiscVReg *rhs, RiscVReg lhsTempReg, RiscVReg rhsTempReg, bool allowOverlap) { *lhs = NormalizeR(inst.src1, allowOverlap ? 0 : inst.dest, lhsTempReg); *rhs = NormalizeR(inst.src2, allowOverlap ? 0 : inst.dest, rhsTempReg); } -RiscVReg RiscVJit::NormalizeR(IRRegIndex rs, IRRegIndex rd, RiscVReg tempReg) { +RiscVReg RiscVJitBackend::NormalizeR(IRRegIndex rs, IRRegIndex rd, RiscVReg tempReg) { // For proper compare, we must sign extend so they both match or don't match. // But don't change pointers, in case one is SP (happens in LittleBigPlanet.) if (gpr.IsImm(rs) && gpr.GetImm(rs) == 0) { diff --git a/Core/MIPS/RiscV/RiscVJit.h b/Core/MIPS/RiscV/RiscVJit.h index 77e47d5abc..ca1d77f68d 100644 --- a/Core/MIPS/RiscV/RiscVJit.h +++ b/Core/MIPS/RiscV/RiscVJit.h @@ -29,30 +29,23 @@ namespace MIPSComp { -// TODO: Separate. -class RiscVJit : public RiscVGen::RiscVCodeBlock, public IRNativeJit, public IRNativeBackend { +class RiscVJitBackend : public RiscVGen::RiscVCodeBlock, public IRNativeBackend { public: - RiscVJit(MIPSState *mipsState); - ~RiscVJit(); + RiscVJitBackend(MIPSState *mipsState, JitOptions &jo); + ~RiscVJitBackend(); - void RunLoopUntil(u64 globalticks) override; + bool DescribeCodePtr(const u8 *ptr, std::string &name) const override; - bool DescribeCodePtr(const u8 *ptr, std::string &name) override; - bool CodeInRange(const u8 *ptr) const override; - bool IsAtDispatchFetch(const u8 *ptr) const override; - const u8 *GetDispatcher() const override; - const u8 *GetCrashHandler() const override; - - void ClearCache() override; - - JitBlockCacheDebugInterface *GetBlockCacheDebugInterface() override; + void GenerateFixedCode() override; + bool CompileBlock(IRBlock *block, int block_num, bool preload) override; + void ClearAllBlocks() override; protected: - bool CompileTargetBlock(IRBlock *block, int block_num, bool preload) override; + const CodeBlockCommon &CodeBlock() const override { + return *this; + } private: - void GenerateFixedCode(const JitOptions &jo); - void RestoreRoundingMode(bool force = false); void ApplyRoundingMode(bool force = false); void MovFromPC(RiscVGen::RiscVReg r); @@ -114,27 +107,34 @@ private: void NormalizeSrc12(IRInst inst, RiscVGen::RiscVReg *lhs, RiscVGen::RiscVReg *rhs, RiscVGen::RiscVReg lhsTempReg, RiscVGen::RiscVReg rhsTempReg, bool allowOverlap); RiscVGen::RiscVReg NormalizeR(IRRegIndex rs, IRRegIndex rd, RiscVGen::RiscVReg tempReg); + // TODO: Maybe just a param to GenerateFixedCode(). + MIPSState *mips_; + JitOptions &jo; RiscVRegCache gpr; RiscVRegCacheFPU fpr; - IRNativeBlockCacheDebugInterface debugInterface_; - - const u8 *enterDispatcher_ = nullptr; const u8 *outerLoop_ = nullptr; const u8 *outerLoopPCInSCRATCH1_ = nullptr; const u8 *dispatcherCheckCoreState_ = nullptr; const u8 *dispatcherPCInSCRATCH1_ = nullptr; - const u8 *dispatcher_ = nullptr; const u8 *dispatcherNoCheck_ = nullptr; - const u8 *dispatcherFetch_ = nullptr; const u8 *applyRoundingMode_ = nullptr; const u8 *saveStaticRegisters_ = nullptr; const u8 *loadStaticRegisters_ = nullptr; - const u8 *crashHandler_ = nullptr; - int jitStartOffset_ = 0; }; +class RiscVJit : public IRNativeJit { +public: + RiscVJit(MIPSState *mipsState) + : IRNativeJit(mipsState), rvBackend_(mipsState, jo) { + Init(rvBackend_); + } + +private: + RiscVJitBackend rvBackend_; +}; + } // namespace MIPSComp