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:
Unknown W. Brackets committed 2013-11-04 07:59:37 -08:00
1 parent baa82e0a9d
commit 732ae13ebb
7 files changed
+118 -49

No files matched your search

+21 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
}
+5
View File
@@ -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);
+7 -3
View File
@@ -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);
+1 -4
View File
@@ -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)
+4 -3
View File
@@ -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);