mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Fast path CallSyscall where possible.
It seems we're spending a decent amount of time there, which isn't entirely unexpected. We can eliminate some things easily.
This commit is contained in:
1 parent
baa82e0a9d
commit
732ae13ebb
7 files changed
+118
-49
No files matched your search
+21
-1
@@ -123,7 +123,14 @@ void XEmitter::ABI_CallFunctionCCCP(void *func, u32 param1, u32 param2,u32 param
|
||||
ABI_RestoreStack(4 * 4);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionPPC(void *func, void *param1, void *param2,u32 param3) {
|
||||
void XEmitter::ABI_CallFunctionP(void *func, void *param1) {
|
||||
ABI_AlignStack(1 * 4);
|
||||
PUSH(32, Imm32((u32)param1));
|
||||
CALL(func);
|
||||
ABI_RestoreStack(1 * 4);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionPPC(void *func, void *param1, void *param2, u32 param3) {
|
||||
ABI_AlignStack(3 * 4);
|
||||
PUSH(32, Imm32(param3));
|
||||
PUSH(32, Imm32((u32)param2));
|
||||
@@ -352,6 +359,19 @@ void XEmitter::ABI_CallFunctionCCCP(void *func, u32 param1, u32 param2, u32 para
|
||||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionP(void *func, void *param1) {
|
||||
MOV(64, R(ABI_PARAM1), Imm64((u64)param1));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), Imm64((u64)func));
|
||||
CALLptr(R(RAX));
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionPPC(void *func, void *param1, void *param2, u32 param3) {
|
||||
MOV(64, R(ABI_PARAM1), Imm64((u64)param1));
|
||||
MOV(64, R(ABI_PARAM2), Imm64((u64)param2));
|
||||
|
||||
+3
-2
@@ -677,8 +677,9 @@ public:
|
||||
void ABI_CallFunctionCC(void *func, u32 param1, u32 param2);
|
||||
void ABI_CallFunctionCCC(void *func, u32 param1, u32 param2, u32 param3);
|
||||
void ABI_CallFunctionCCP(void *func, u32 param1, u32 param2, void *param3);
|
||||
void ABI_CallFunctionCCCP(void *func, u32 param1, u32 param2,u32 param3, void *param4);
|
||||
void ABI_CallFunctionPPC(void *func, void *param1, void *param2,u32 param3);
|
||||
void ABI_CallFunctionCCCP(void *func, u32 param1, u32 param2, u32 param3, void *param4);
|
||||
void ABI_CallFunctionP(void *func, void *param1);
|
||||
void ABI_CallFunctionPPC(void *func, void *param1, void *param2, u32 param3);
|
||||
void ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2);
|
||||
void ABI_CallFunctionACC(void *func, const Gen::OpArg &arg1, u32 param2, u32 param3);
|
||||
void ABI_CallFunctionA(void *func, const Gen::OpArg &arg1);
|
||||
|
||||
+77
-36
@@ -365,7 +365,7 @@ inline static void SetDeadbeefRegs()
|
||||
currentMIPS->hi = 0xDEADBEEF;
|
||||
}
|
||||
|
||||
inline void hleFinishSyscall(int modulenum, int funcnum)
|
||||
inline void hleFinishSyscall(const HLEFunction &info)
|
||||
{
|
||||
if ((hleAfterSyscall & HLE_AFTER_SKIP_DEADBEEF) == 0)
|
||||
SetDeadbeefRegs();
|
||||
@@ -386,7 +386,7 @@ inline void hleFinishSyscall(int modulenum, int funcnum)
|
||||
|
||||
if ((hleAfterSyscall & HLE_AFTER_DEBUG_BREAK) != 0)
|
||||
{
|
||||
if (!hleExecuteDebugBreak(moduleDB[modulenum].funcTable[funcnum]))
|
||||
if (!hleExecuteDebugBreak(info))
|
||||
{
|
||||
// We'll do it next syscall.
|
||||
hleAfterSyscall = HLE_AFTER_DEBUG_BREAK;
|
||||
@@ -435,6 +435,69 @@ inline void updateSyscallStats(int modulenum, int funcnum, double total)
|
||||
}
|
||||
}
|
||||
|
||||
inline void CallSyscallWithFlags(const HLEFunction *info)
|
||||
{
|
||||
const u32 flags = info->flags;
|
||||
if ((flags & HLE_NOT_DISPATCH_SUSPENDED) && !__KernelIsDispatchEnabled())
|
||||
{
|
||||
DEBUG_LOG(HLE, "%s: dispatch suspended", info->name);
|
||||
RETURN(SCE_KERNEL_ERROR_CAN_NOT_WAIT);
|
||||
}
|
||||
else if ((flags & HLE_NOT_IN_INTERRUPT) && __IsInInterrupt())
|
||||
{
|
||||
DEBUG_LOG(HLE, "%s: in interrupt", info->name);
|
||||
RETURN(SCE_KERNEL_ERROR_ILLEGAL_CONTEXT);
|
||||
}
|
||||
else
|
||||
info->func();
|
||||
|
||||
if (hleAfterSyscall != HLE_AFTER_NOTHING)
|
||||
hleFinishSyscall(*info);
|
||||
else
|
||||
SetDeadbeefRegs();
|
||||
}
|
||||
|
||||
inline void CallSyscallWithoutFlags(const HLEFunction *info)
|
||||
{
|
||||
info->func();
|
||||
|
||||
if (hleAfterSyscall != HLE_AFTER_NOTHING)
|
||||
hleFinishSyscall(*info);
|
||||
else
|
||||
SetDeadbeefRegs();
|
||||
}
|
||||
|
||||
const HLEFunction *GetSyscallInfo(MIPSOpcode op)
|
||||
{
|
||||
u32 callno = (op >> 6) & 0xFFFFF; //20 bits
|
||||
int funcnum = callno & 0xFFF;
|
||||
int modulenum = (callno & 0xFF000) >> 12;
|
||||
if (funcnum == 0xfff)
|
||||
{
|
||||
ERROR_LOG(HLE,"Unknown syscall: Module: %s", modulenum > (int) moduleDB.size() ? "(unknown)" : moduleDB[modulenum].name);
|
||||
return NULL;
|
||||
}
|
||||
return &moduleDB[modulenum].funcTable[funcnum];
|
||||
}
|
||||
|
||||
void *GetQuickSyscallFunc(MIPSOpcode op)
|
||||
{
|
||||
// TODO: Clear jit cache on g_Config.bShowDebugStats change?
|
||||
if (g_Config.bShowDebugStats)
|
||||
return NULL;
|
||||
|
||||
const HLEFunction *info = GetSyscallInfo(op);
|
||||
if (!info || !info->func)
|
||||
return NULL;
|
||||
|
||||
// TODO: Do this with a flag?
|
||||
if (op == GetSyscallOp("FakeSysCalls", NID_IDLE))
|
||||
return (void *)info->func;
|
||||
if (info->flags != 0)
|
||||
return (void *)&CallSyscallWithFlags;
|
||||
return (void *)&CallSyscallWithoutFlags;
|
||||
}
|
||||
|
||||
void CallSyscall(MIPSOpcode op)
|
||||
{
|
||||
double start = 0.0; // need to initialize to fix the race condition where g_Config.bShowDebugStats is enabled in the middle of this func.
|
||||
@@ -443,49 +506,27 @@ void CallSyscall(MIPSOpcode op)
|
||||
time_update();
|
||||
start = time_now_d();
|
||||
}
|
||||
u32 callno = (op >> 6) & 0xFFFFF; //20 bits
|
||||
int funcnum = callno & 0xFFF;
|
||||
int modulenum = (callno & 0xFF000) >> 12;
|
||||
if (funcnum == 0xfff)
|
||||
const HLEFunction *info = GetSyscallInfo(op);
|
||||
if (info)
|
||||
{
|
||||
ERROR_LOG(HLE,"Unknown syscall: Module: %s", modulenum > (int) moduleDB.size() ? "(unknown)" : moduleDB[modulenum].name);
|
||||
return;
|
||||
}
|
||||
HLEFunc func = moduleDB[modulenum].funcTable[funcnum].func;
|
||||
if (func)
|
||||
{
|
||||
// TODO: Move to jit/interp.
|
||||
u32 flags = moduleDB[modulenum].funcTable[funcnum].flags;
|
||||
if (flags != 0)
|
||||
if (info->func)
|
||||
{
|
||||
if ((flags & HLE_NOT_DISPATCH_SUSPENDED) && !__KernelIsDispatchEnabled())
|
||||
{
|
||||
DEBUG_LOG(HLE, "%s: dispatch suspended", moduleDB[modulenum].funcTable[funcnum].name);
|
||||
RETURN(SCE_KERNEL_ERROR_CAN_NOT_WAIT);
|
||||
}
|
||||
else if ((flags & HLE_NOT_IN_INTERRUPT) && __IsInInterrupt())
|
||||
{
|
||||
DEBUG_LOG(HLE, "%s: in interrupt", moduleDB[modulenum].funcTable[funcnum].name);
|
||||
RETURN(SCE_KERNEL_ERROR_ILLEGAL_CONTEXT);
|
||||
}
|
||||
if (op == GetSyscallOp("FakeSysCalls", NID_IDLE))
|
||||
info->func();
|
||||
else if (info->flags != 0)
|
||||
CallSyscallWithFlags(info);
|
||||
else
|
||||
func();
|
||||
CallSyscallWithoutFlags(info);
|
||||
}
|
||||
else
|
||||
func();
|
||||
|
||||
if (hleAfterSyscall != HLE_AFTER_NOTHING)
|
||||
hleFinishSyscall(modulenum, funcnum);
|
||||
else
|
||||
SetDeadbeefRegs();
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG_REPORT(HLE, "Unimplemented HLE function %s", moduleDB[modulenum].funcTable[funcnum].name);
|
||||
ERROR_LOG_REPORT(HLE, "Unimplemented HLE function %s", info->name);
|
||||
}
|
||||
if (g_Config.bShowDebugStats)
|
||||
{
|
||||
time_update();
|
||||
u32 callno = (op >> 6) & 0xFFFFF; //20 bits
|
||||
int funcnum = callno & 0xFFF;
|
||||
int modulenum = (callno & 0xFF000) >> 12;
|
||||
updateSyscallStats(modulenum, funcnum, time_now_d() - start);
|
||||
}
|
||||
}
|
||||
@@ -120,3 +120,8 @@ bool WriteSyscall(const char *module, u32 nib, u32 address);
|
||||
void CallSyscall(MIPSOpcode op);
|
||||
void WriteFuncStub(u32 stubAddr, u32 symAddr);
|
||||
void WriteFuncMissingStub(u32 stubAddr, u32 nid);
|
||||
|
||||
const HLEFunction *GetSyscallInfo(MIPSOpcode op);
|
||||
// For jit, takes arg: const HLEFunction *
|
||||
void *GetQuickSyscallFunc(MIPSOpcode op);
|
||||
|
||||
@@ -425,9 +425,13 @@ void Jit::Comp_Syscall(MIPSOpcode op)
|
||||
js.downcountAmount = -offset;
|
||||
|
||||
SaveDowncount();
|
||||
// Skip the CallSyscall overhead for __KernelIdle, which is called a lot.
|
||||
if (op == GetSyscallOp("FakeSysCalls", NID_IDLE))
|
||||
QuickCallFunction(R1, (void *)GetFunc("FakeSysCalls", NID_IDLE)->func);
|
||||
// Skip the CallSyscall where possible.
|
||||
void *quickFunc = GetQuickSyscallFunc(op);
|
||||
if (quickFunc)
|
||||
{
|
||||
MOVI2R(R0, (u32)(intptr_t)GetSyscallInfo(op));
|
||||
QuickCallFunction(R1, quickFunc);
|
||||
}
|
||||
else
|
||||
{
|
||||
MOVI2R(R0, op.encoding);
|
||||
|
||||
@@ -159,10 +159,7 @@ namespace MIPSInt
|
||||
mipsr4k.pc += 4;
|
||||
}
|
||||
mipsr4k.inDelaySlot = false;
|
||||
if (op == GetSyscallOp("FakeSysCalls", NID_IDLE))
|
||||
GetFunc("FakeSysCalls", NID_IDLE)->func();
|
||||
else
|
||||
CallSyscall(op);
|
||||
CallSyscall(op);
|
||||
}
|
||||
|
||||
void Int_Sync(MIPSOpcode op)
|
||||
|
||||
@@ -634,9 +634,10 @@ void Jit::Comp_Syscall(MIPSOpcode op)
|
||||
WriteDowncount(offset);
|
||||
js.downcountAmount = -offset;
|
||||
|
||||
// Skip the CallSyscall overhead for __KernelIdle, which is called a lot.
|
||||
if (op == GetSyscallOp("FakeSysCalls", NID_IDLE))
|
||||
ABI_CallFunction((void *)GetFunc("FakeSysCalls", NID_IDLE)->func);
|
||||
// Skip the CallSyscall where possible.
|
||||
void *quickFunc = GetQuickSyscallFunc(op);
|
||||
if (quickFunc)
|
||||
ABI_CallFunctionP(quickFunc, (void *)GetSyscallInfo(op));
|
||||
else
|
||||
ABI_CallFunctionC((void *)&CallSyscall, op.encoding);
|
||||
|
||||
|
||||
Reference in new issue
Block a user