diff --git a/Common/ABI.cpp b/Common/ABI.cpp index 60e8c927e1..583a357128 100644 --- a/Common/ABI.cpp +++ b/Common/ABI.cpp @@ -442,7 +442,7 @@ void XEmitter::ABI_CallFunctionPPC(const void *func, void *param1, void *param2, // Pass a register as a parameter. void XEmitter::ABI_CallFunctionR(const void *func, X64Reg reg1) { if (reg1 != ABI_PARAM1) - MOV(32, R(ABI_PARAM1), R(reg1)); + MOV(64, R(ABI_PARAM1), R(reg1)); u64 distance = u64(func) - (u64(code) + 5); if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { diff --git a/Common/Arm64Emitter.cpp b/Common/Arm64Emitter.cpp index afddd61045..6cdab2596b 100644 --- a/Common/Arm64Emitter.cpp +++ b/Common/Arm64Emitter.cpp @@ -1044,8 +1044,21 @@ void ARM64XEmitter::BL(const void* ptr) } void ARM64XEmitter::QuickCallFunction(ARM64Reg scratchreg, const void *func) { - s64 distance = (s64)func - (s64)m_code; - distance >>= 2; // Can only branch to opcode-aligned (4) addresses + s64 distance = ((s64)func - (s64)m_code) >> 2; + if (!IsInRangeImm26(distance)) { + // WARN_LOG(Log::JIT, "Distance too far in function call (%p to %p)! Using scratch.", m_code, func); + MOVI2R(scratchreg, (uintptr_t)func); + BLR(scratchreg); + } else { + BL(func); + } +} + +void ARM64XEmitter::QuickCallFunctionR(ARM64Reg scratchreg, const void *func, ARM64Reg arg) { + s64 distance = ((s64)func - (s64)m_code) >> 2; + if (arg != X0) { + MOV(X0, arg); + } if (!IsInRangeImm26(distance)) { // WARN_LOG(Log::JIT, "Distance too far in function call (%p to %p)! Using scratch.", m_code, func); MOVI2R(scratchreg, (uintptr_t)func); diff --git a/Common/Arm64Emitter.h b/Common/Arm64Emitter.h index b1d325871f..19fef73745 100644 --- a/Common/Arm64Emitter.h +++ b/Common/Arm64Emitter.h @@ -776,6 +776,11 @@ public: template void QuickCallFunction(ARM64Reg scratchreg, T func) { QuickCallFunction(scratchreg, (const void *)func); } + void QuickCallFunctionR(ARM64Reg scratchreg, const void *func, ARM64Reg arg); + template void QuickCallFunctionR(ARM64Reg scratchreg, T func, ARM64Reg arg) { + QuickCallFunctionR(scratchreg, (const void *)func, arg); + } + }; class ARM64FloatEmitter diff --git a/Common/ArmEmitter.cpp b/Common/ArmEmitter.cpp index e974196f44..cfa1b8af1e 100644 --- a/Common/ArmEmitter.cpp +++ b/Common/ArmEmitter.cpp @@ -557,6 +557,18 @@ void ARMXEmitter::QuickCallFunction(ARMReg reg, const void *func) { } } +void ARMXEmitter::QuickCallFunctionR(ARMReg reg, const void *func, ARMReg arg) { + if (arg != R0) { + MOV(R0, arg); + } + if (BLInRange(func)) { + BL(func); + } else { + MOVP2R(reg, func); + BL(reg); + } +} + void ARMXEmitter::SetCodePointer(u8 *ptr, u8 *writePtr) { code = ptr; diff --git a/Common/ArmEmitter.h b/Common/ArmEmitter.h index c6fe15dc17..f2512bf1cf 100644 --- a/Common/ArmEmitter.h +++ b/Common/ArmEmitter.h @@ -854,6 +854,10 @@ public: template void QuickCallFunction(ARMReg scratchreg, T func) { QuickCallFunction(scratchreg, (const void *)func); } + void QuickCallFunctionR(ARMReg scratchreg, const void *func, ARMReg arg); + template void QuickCallFunctionR(ARMReg scratchreg, T func, ARMReg arg) { + QuickCallFunctionR(scratchreg, (const void *)func, arg); + } // Wrapper around MOVT/MOVW with fallbacks. void MOVI2R(ARMReg reg, u32 val, bool optimize = true); diff --git a/Common/LoongArch64Emitter.h b/Common/LoongArch64Emitter.h index 30de62f12b..134b5de61d 100644 --- a/Common/LoongArch64Emitter.h +++ b/Common/LoongArch64Emitter.h @@ -165,7 +165,15 @@ public: static_assert(std::is_function::value, "QuickCallFunction without function"); QuickCallFunction((const u8 *)func, scratchreg); } - + void QuickCallFunctionR(const u8 *func, LoongArch64Reg arg, LoongArch64Reg scratchreg = R_RA) { + MOVE(LoongArch64Reg::X4, arg); + QuickJump(scratchreg, R_RA, func); + } + template + void QuickCallFunctionR(T *func, LoongArch64Reg arg, LoongArch64Reg scratchreg = R_RA) { + static_assert(std::is_function::value, "QuickCallFunction without function"); + QuickCallFunctionR((const u8 *)func, arg, scratchreg); + } // https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html // https://github.com/loongson-community/loongarch-opcodes/ diff --git a/Common/RiscVEmitter.h b/Common/RiscVEmitter.h index 651ab727c9..be6e2e986d 100644 --- a/Common/RiscVEmitter.h +++ b/Common/RiscVEmitter.h @@ -226,6 +226,17 @@ public: QuickCallFunction((const u8 *)func, scratchreg); } + void QuickCallFunctionR(const u8 *func, RiscVReg arg, RiscVReg scratchreg = R_RA) { + if (arg != RiscVReg::X10) { // A0 + MV(RiscVReg::X10, arg); + } + QuickJAL(scratchreg, R_RA, func); + } + template + void QuickCallFunctionR(T *func, RiscVReg arg, RiscVReg scratchreg = R_RA) { + static_assert(std::is_function::value, "QuickCallFunction without function"); + QuickCallFunctionR((const u8 *)func, arg, scratchreg); + } void LUI(RiscVReg rd, s32 simm32); void AUIPC(RiscVReg rd, s32 simm32); diff --git a/Core/CoreTiming.cpp b/Core/CoreTiming.cpp index a80e919982..b8a775b6a6 100644 --- a/Core/CoreTiming.cpp +++ b/Core/CoreTiming.cpp @@ -379,8 +379,7 @@ void ForceCheck(MIPSState *mips) { #endif } -void Advance() { - MIPSState *mips = currentMIPS; // TODO: Move to parameter +void Advance(MIPSState *mips) { PROFILE_THIS_SCOPE("advance"); int cyclesExecuted = slicelength - mips->downcount; globalTimer += cyclesExecuted; diff --git a/Core/CoreTiming.h b/Core/CoreTiming.h index 5a97c103ab..725ef6dd72 100644 --- a/Core/CoreTiming.h +++ b/Core/CoreTiming.h @@ -113,7 +113,7 @@ namespace CoreTiming { const Event *GetFirstEvent(); void RemoveEvent(int event_type); bool IsScheduled(int event_type); - void Advance(); + void Advance(MIPSState *mips); void ForceCheck(MIPSState *mips); // Pretend that the main CPU has executed enough cycles to reach the next event. diff --git a/Core/HLE/HLE.cpp b/Core/HLE/HLE.cpp index 19f65bd9b3..ccb8d0bf69 100644 --- a/Core/HLE/HLE.cpp +++ b/Core/HLE/HLE.cpp @@ -605,8 +605,8 @@ void hleEnqueueCall(u32 func, int argc, const u32 *argv, PSPAction *afterAction) hleAfterSyscall |= HLE_AFTER_QUEUED_CALLS; } -void hleFlushCalls() { - u32 &sp = currentMIPS->r[MIPS_REG_SP]; +static void hleFlushCalls(MIPSState *mips) { + u32 &sp = mips->r[MIPS_REG_SP]; PSPPointer stackData; _dbg_assert_(g_stackSize == 0); VERBOSE_LOG(Log::HLE, "Flushing %d HLE mips calls from %s, sp=%08x", (int)enqueuedMipsCalls.size(), g_stackSize ? g_stack[0]->name : "?", sp); @@ -615,15 +615,15 @@ void hleFlushCalls() { sp -= sizeof(HLEMipsCallStack); stackData.ptr = sp; stackData->nextOff = 0xFFFFFFFF; - stackData->ra = currentMIPS->pc; - stackData->v0 = currentMIPS->r[MIPS_REG_V0]; - stackData->v1 = currentMIPS->r[MIPS_REG_V1]; + stackData->ra = mips->pc; + stackData->v0 = mips->r[MIPS_REG_V0]; + stackData->v1 = mips->r[MIPS_REG_V1]; // Now we'll set up the first in the chain. - currentMIPS->pc = enqueuedMipsCalls[0].func; - currentMIPS->r[MIPS_REG_RA] = HLEMipsCallReturnAddress(); + mips->pc = enqueuedMipsCalls[0].func; + mips->r[MIPS_REG_RA] = HLEMipsCallReturnAddress(); for (int i = 0; i < (int)enqueuedMipsCalls[0].args.size(); i++) { - currentMIPS->r[MIPS_REG_A0 + i] = enqueuedMipsCalls[0].args[i]; + mips->r[MIPS_REG_A0 + i] = enqueuedMipsCalls[0].args[i]; } // For stack info, process the first enqueued call last, so we run it first. @@ -653,6 +653,7 @@ void hleFlushCalls() { DEBUG_LOG(Log::HLE, "Executing HLE mips call at %08x, sp=%08x", currentMIPS->pc, sp); } +// This is a HLE function. void HLEReturnFromMipsCall() { u32 &sp = currentMIPS->r[MIPS_REG_SP]; PSPPointer stackData; @@ -777,7 +778,7 @@ static void hleFinishSyscall(const HLEFunction *info) { SetDeadbeefRegs(); if ((hleAfterSyscall & HLE_AFTER_QUEUED_CALLS) != 0) - hleFlushCalls(); + hleFlushCalls(currentMIPS); if ((hleAfterSyscall & HLE_AFTER_CURRENT_CALLBACKS) != 0 && (hleAfterSyscall & HLE_AFTER_RESCHED_CALLBACKS) == 0) __KernelForceCallbacks(); @@ -806,15 +807,13 @@ void hleFinishSyscallAfterGe() { hleFinishSyscall(nullptr); } -static void updateSyscallStats(int modulenum, int funcnum, double total) -{ +static void updateSyscallStats(int modulenum, int funcnum, double total) { const char *name = moduleDB[modulenum].funcTable[funcnum].name; // Ignore this one, especially for msInSyscalls (although that ignores CoreTiming events.) if (0 == strcmp(name, "_sceKernelIdle")) return; - if (total > kernelStats.slowestSyscallTime) - { + if (total > kernelStats.slowestSyscallTime) { kernelStats.slowestSyscallTime = total; kernelStats.slowestSyscallName = name; } @@ -822,20 +821,15 @@ static void updateSyscallStats(int modulenum, int funcnum, double total) KernelStatsSyscall statCall(modulenum, funcnum); auto summedStat = kernelStats.summedMsInSyscalls.find(statCall); - if (summedStat == kernelStats.summedMsInSyscalls.end()) - { + if (summedStat == kernelStats.summedMsInSyscalls.end()) { kernelStats.summedMsInSyscalls[statCall] = total; - if (total > kernelStats.summedSlowestSyscallTime) - { + if (total > kernelStats.summedSlowestSyscallTime) { kernelStats.summedSlowestSyscallTime = total; kernelStats.summedSlowestSyscallName = name; } - } - else - { + } else { double newTotal = kernelStats.summedMsInSyscalls[statCall] += total; - if (newTotal > kernelStats.summedSlowestSyscallTime) - { + if (newTotal > kernelStats.summedSlowestSyscallTime) { kernelStats.summedSlowestSyscallTime = newTotal; kernelStats.summedSlowestSyscallName = name; } diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index c92155a614..4c0e141f4c 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -1638,7 +1638,7 @@ void __KernelReSchedule(const char *reason) __KernelCheckCallbacks(); // Execute any pending events while we're doing scheduling. - CoreTiming::Advance(); + CoreTiming::Advance(currentMIPS); if (__IsInInterrupt() || !__KernelIsDispatchEnabled()) { // Threads don't get changed within interrupts or while dispatch is disabled. reason = "In Interrupt Or Callback"; diff --git a/Core/MIPS/ARM/ArmAsm.cpp b/Core/MIPS/ARM/ArmAsm.cpp index 6773e01123..df4735c5ea 100644 --- a/Core/MIPS/ARM/ArmAsm.cpp +++ b/Core/MIPS/ARM/ArmAsm.cpp @@ -159,7 +159,7 @@ void ArmJit::GenerateFixedCode() { outerLoop = GetCodePtr(); SaveDowncount(); RestoreRoundingMode(true); - QuickCallFunction(R0, &CoreTiming::Advance); + QuickCallFunctionR(R1, &CoreTiming::Advance, CTXREG); ApplyRoundingMode(true); RestoreDowncount(); FixupBranch skipToCoreStateCheck = B(); //skip the downcount check diff --git a/Core/MIPS/ARM64/Arm64Asm.cpp b/Core/MIPS/ARM64/Arm64Asm.cpp index 245d99c2e1..d2c83eaffd 100644 --- a/Core/MIPS/ARM64/Arm64Asm.cpp +++ b/Core/MIPS/ARM64/Arm64Asm.cpp @@ -204,7 +204,7 @@ void Arm64Jit::GenerateFixedCode(const JitOptions &jo) { outerLoop = GetCodePtr(); SaveStaticRegisters(); // Advance can change the downcount, so must save/restore RestoreRoundingMode(true); - QuickCallFunction(SCRATCH1_64, &CoreTiming::Advance); + QuickCallFunctionR(SCRATCH1_64, &CoreTiming::Advance, CTXREG); ApplyRoundingMode(true); LoadStaticRegisters(); FixupBranch skipToCoreStateCheck = B(); //skip the downcount check diff --git a/Core/MIPS/ARM64/Arm64IRAsm.cpp b/Core/MIPS/ARM64/Arm64IRAsm.cpp index fd518d4a35..2b64b48c72 100644 --- a/Core/MIPS/ARM64/Arm64IRAsm.cpp +++ b/Core/MIPS/ARM64/Arm64IRAsm.cpp @@ -169,7 +169,7 @@ void Arm64JitBackend::GenerateFixedCode(MIPSState *mipsState) { SaveStaticRegisters(); // Advance can change the downcount, so must save/restore RestoreRoundingMode(true); WriteDebugProfilerStatus(IRProfilerStatus::TIMER_ADVANCE); - QuickCallFunction(SCRATCH1_64, &CoreTiming::Advance); + QuickCallFunctionR(SCRATCH1_64, &CoreTiming::Advance, CTXREG); WriteDebugProfilerStatus(IRProfilerStatus::IN_JIT); ApplyRoundingMode(true); LoadStaticRegisters(); diff --git a/Core/MIPS/IR/IRJit.cpp b/Core/MIPS/IR/IRJit.cpp index b647ae6cb0..b5611d210e 100644 --- a/Core/MIPS/IR/IRJit.cpp +++ b/Core/MIPS/IR/IRJit.cpp @@ -175,7 +175,7 @@ void IRJit::RunLoopUntil(u64 globalticks) { MIPSState *mips = mips_; while (true) { // RestoreRoundingMode(true); - CoreTiming::Advance(); + CoreTiming::Advance(currentMIPS); // ApplyRoundingMode(true); if (coreState != 0) { break; diff --git a/Core/MIPS/LoongArch64/LoongArch64Asm.cpp b/Core/MIPS/LoongArch64/LoongArch64Asm.cpp index dac27da7c5..2caeb770c1 100644 --- a/Core/MIPS/LoongArch64/LoongArch64Asm.cpp +++ b/Core/MIPS/LoongArch64/LoongArch64Asm.cpp @@ -134,7 +134,7 @@ void LoongArch64JitBackend::GenerateFixedCode(MIPSState *mipsState) { SaveStaticRegisters(); RestoreRoundingMode(true); WriteDebugProfilerStatus(IRProfilerStatus::TIMER_ADVANCE); - QuickCallFunction(&CoreTiming::Advance, R20); + QuickCallFunctionR(&CoreTiming::Advance, CTXREG, R20); WriteDebugProfilerStatus(IRProfilerStatus::IN_JIT); ApplyRoundingMode(true); LoadStaticRegisters(); diff --git a/Core/MIPS/MIPS.cpp b/Core/MIPS/MIPS.cpp index 57b7aad9b5..adf6e08480 100644 --- a/Core/MIPS/MIPS.cpp +++ b/Core/MIPS/MIPS.cpp @@ -325,7 +325,7 @@ void MIPSState::DoState(PointerWrap &p) { void MIPSState::SingleStep() { int cycles = MIPS_SingleStep(this); downcount -= cycles; - CoreTiming::Advance(); + CoreTiming::Advance(currentMIPS); } // returns 1 if reached ticks limit diff --git a/Core/MIPS/MIPSTables.cpp b/Core/MIPS/MIPSTables.cpp index 75f4c937eb..e0da966bf0 100644 --- a/Core/MIPS/MIPSTables.cpp +++ b/Core/MIPS/MIPSTables.cpp @@ -1197,9 +1197,9 @@ static void RunUntilDowncountZeroWithChecks(MIPSState *mips, u64 globalTicks) { int MIPSInterpret_RunUntil(MIPSState *mips, u64 globalTicks) { while (coreState == CORE_RUNNING_CPU) { - CoreTiming::Advance(); + CoreTiming::Advance(mips); - uint64_t ticksLeft = globalTicks - CoreTiming::GetTicks(currentMIPS); + uint64_t ticksLeft = globalTicks - CoreTiming::GetTicks(mips); if (g_breakpoints.HasBreakPoints() || g_breakpoints.HasMemChecks() || ticksLeft <= mips->downcount) { RunUntilDowncountZeroWithChecks(mips, globalTicks); } else { diff --git a/Core/MIPS/RiscV/RiscVAsm.cpp b/Core/MIPS/RiscV/RiscVAsm.cpp index c88d961a97..396c45ec20 100644 --- a/Core/MIPS/RiscV/RiscVAsm.cpp +++ b/Core/MIPS/RiscV/RiscVAsm.cpp @@ -143,7 +143,7 @@ void RiscVJitBackend::GenerateFixedCode(MIPSState *mipsState) { SaveStaticRegisters(); RestoreRoundingMode(true); WriteDebugProfilerStatus(IRProfilerStatus::TIMER_ADVANCE); - QuickCallFunction(&CoreTiming::Advance, X7); + QuickCallFunctionR(&CoreTiming::Advance, CTXREG, X7); WriteDebugProfilerStatus(IRProfilerStatus::IN_JIT); ApplyRoundingMode(true); LoadStaticRegisters(); diff --git a/Core/MIPS/x86/Asm.cpp b/Core/MIPS/x86/Asm.cpp index 0c5d5924f0..126d915ea8 100644 --- a/Core/MIPS/x86/Asm.cpp +++ b/Core/MIPS/x86/Asm.cpp @@ -125,7 +125,8 @@ void Jit::GenerateFixedCode(JitOptions &jo) { outerLoop = GetCodePtr(); RestoreRoundingMode(true); - ABI_CallFunction(reinterpret_cast(&CoreTiming::Advance)); + LEA(PTRBITS, ECX, MDisp(CTXREG, -(s32)offsetof(MIPSState, f[0]))); // Adjust to get the real pointer. + ABI_CallFunctionR(reinterpret_cast(&CoreTiming::Advance), ECX); ApplyRoundingMode(true); FixupBranch skipToCoreStateCheck = J(); //skip the downcount check diff --git a/Core/MIPS/x86/X64IRAsm.cpp b/Core/MIPS/x86/X64IRAsm.cpp index 5cf4136930..a3b273f587 100644 --- a/Core/MIPS/x86/X64IRAsm.cpp +++ b/Core/MIPS/x86/X64IRAsm.cpp @@ -167,7 +167,8 @@ void X64JitBackend::GenerateFixedCode(MIPSState *mipsState) { SaveStaticRegisters(); RestoreRoundingMode(true); WriteDebugProfilerStatus(IRProfilerStatus::TIMER_ADVANCE); - ABI_CallFunction(reinterpret_cast(&CoreTiming::Advance)); + LEA(PTRBITS, ECX, MDisp(CTXREG, -(s32)offsetof(MIPSState, f[0]))); // Adjust to get the real pointer. + ABI_CallFunctionR(reinterpret_cast(&CoreTiming::Advance), ECX); WriteDebugProfilerStatus(IRProfilerStatus::IN_JIT); ApplyRoundingMode(true); LoadStaticRegisters(); diff --git a/unittest/JitHarness.cpp b/unittest/JitHarness.cpp index a73ed48d18..a1098e6bef 100644 --- a/unittest/JitHarness.cpp +++ b/unittest/JitHarness.cpp @@ -147,16 +147,6 @@ bool TestJit() { u32 addr = currentMIPS->pc; DebugInterface *dbg = currentDebugMIPS; for (int i = 0; i < 100; ++i) { - /* - // VFPU ops aren't supported by MIPSAsm yet. - *p++ = 0xD03C0000 | (1 << 7) | (1 << 15) | (7 << 8); - *p++ = 0xD03C0000 | (1 << 7) | (1 << 15); - *p++ = 0xD03C0000 | (1 << 7) | (1 << 15) | (7 << 8); - *p++ = 0xD03C0000 | (1 << 7) | (1 << 15) | (7 << 8); - *p++ = 0xD03C0000 | (1 << 7) | (1 << 15) | (7 << 8); - *p++ = 0xD03C0000 | (1 << 7) | (1 << 15) | (7 << 8); - *p++ = 0xD03C0000 | (1 << 7) | (1 << 15) | (7 << 8); - */ std::string error; for (size_t j = 0; j < ARRAY_SIZE(lines); ++j) { p++; @@ -192,7 +182,7 @@ bool TestJit() { jit_speed = ExecCPUTest(); #if !PPSSPP_PLATFORM(MAC) mipsr4k.UpdateCore(CPUCore::JIT_IR); - jit_ir_speed = ExecCPUTest(false); + jit_ir_speed = ExecCPUTest(false); // not clearing, so the below can do things. #endif // Disassemble