summaryrefslogtreecommitdiff
path: root/Source/Core/Common
diff options
context:
space:
mode:
authorPierre Bourdon <delroth@gmail.com>2014-03-09 00:02:47 +0100
committerPierre Bourdon <delroth@gmail.com>2014-03-09 00:02:47 +0100
commit1fbfc4902a4569c2b77a514b353dddc1e0277a3c (patch)
treea8a014ad9dcd33a22ed5f23196cec7fdaca22b71 /Source/Core/Common
parent886060aaf7dbeb5b6dd36390b2adf64ccacf9e85 (diff)
parent8802770a85f7bc452c15b754beef7f28fe2a2033 (diff)
Merge pull request #114 from delroth/mmio-optimization
MMIO reads JIT optimization
Diffstat (limited to 'Source/Core/Common')
-rw-r--r--Source/Core/Common/x64ABI.cpp48
-rw-r--r--Source/Core/Common/x64Emitter.h29
2 files changed, 74 insertions, 3 deletions
diff --git a/Source/Core/Common/x64ABI.cpp b/Source/Core/Common/x64ABI.cpp
index 6f423eaa6a..0116212485 100644
--- a/Source/Core/Common/x64ABI.cpp
+++ b/Source/Core/Common/x64ABI.cpp
@@ -176,6 +176,14 @@ void XEmitter::ABI_CallFunctionCC(void *func, u32 param1, u32 param2) {
ABI_RestoreStack(2 * 4);
}
+void XEmitter::ABI_CallFunctionCP(void *func, u32 param1, void *param2) {
+ ABI_AlignStack(2 * 4);
+ PUSH(32, Imm32((u32)param2));
+ PUSH(32, Imm32(param1));
+ CALL(func);
+ ABI_RestoreStack(2 * 4);
+}
+
void XEmitter::ABI_CallFunctionCCC(void *func, u32 param1, u32 param2, u32 param3) {
ABI_AlignStack(3 * 4);
PUSH(32, Imm32(param3));
@@ -204,6 +212,14 @@ void XEmitter::ABI_CallFunctionCCCP(void *func, u32 param1, u32 param2,u32 param
ABI_RestoreStack(4 * 4);
}
+void XEmitter::ABI_CallFunctionPC(void *func, void *param1, u32 param2) {
+ ABI_AlignStack(3 * 4);
+ PUSH(32, Imm32(param2));
+ PUSH(32, Imm32((u32)param1));
+ CALL(func);
+ ABI_RestoreStack(3 * 4);
+}
+
void XEmitter::ABI_CallFunctionPPC(void *func, void *param1, void *param2,u32 param3) {
ABI_AlignStack(3 * 4);
PUSH(32, Imm32(param3));
@@ -344,6 +360,22 @@ void XEmitter::ABI_CallFunctionCC(void *func, u32 param1, u32 param2) {
ABI_RestoreStack(0);
}
+void XEmitter::ABI_CallFunctionCP(void *func, u32 param1, void *param2) {
+ ABI_AlignStack(0);
+ MOV(32, R(ABI_PARAM1), Imm32(param1));
+ MOV(64, R(ABI_PARAM2), Imm64((u64)param2));
+ 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);
+ }
+ ABI_RestoreStack(0);
+}
+
void XEmitter::ABI_CallFunctionCCC(void *func, u32 param1, u32 param2, u32 param3) {
ABI_AlignStack(0);
MOV(32, R(ABI_PARAM1), Imm32(param1));
@@ -396,6 +428,22 @@ void XEmitter::ABI_CallFunctionCCCP(void *func, u32 param1, u32 param2, u32 para
ABI_RestoreStack(0);
}
+void XEmitter::ABI_CallFunctionPC(void *func, void *param1, u32 param2) {
+ ABI_AlignStack(0);
+ MOV(64, R(ABI_PARAM1), Imm64((u64)param1));
+ MOV(32, R(ABI_PARAM2), Imm32(param2));
+ 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);
+ }
+ ABI_RestoreStack(0);
+}
+
void XEmitter::ABI_CallFunctionPPC(void *func, void *param1, void *param2, u32 param3) {
ABI_AlignStack(0);
MOV(64, R(ABI_PARAM1), Imm64((u64)param1));
diff --git a/Source/Core/Common/x64Emitter.h b/Source/Core/Common/x64Emitter.h
index f8acb6fe95..b35fff3319 100644
--- a/Source/Core/Common/x64Emitter.h
+++ b/Source/Core/Common/x64Emitter.h
@@ -8,6 +8,7 @@
#include <cstddef>
#include <cstring>
+#include <functional>
#include "Common/Common.h"
#include "Common/MemoryUtil.h"
@@ -171,7 +172,7 @@ private:
u16 indexReg;
};
-inline OpArg M(void *ptr) {return OpArg((u64)ptr, (int)SCALE_RIP);}
+inline OpArg M(const void *ptr) {return OpArg((u64)ptr, (int)SCALE_RIP);}
inline OpArg R(X64Reg value) {return OpArg(0, SCALE_NONE, value);}
inline OpArg MatR(X64Reg value) {return OpArg(0, SCALE_ATREG, value);}
inline OpArg MDisp(X64Reg value, int offset) {
@@ -194,9 +195,9 @@ inline OpArg Imm16(u16 imm) {return OpArg(imm, SCALE_IMM16);} //rarely used
inline OpArg Imm32(u32 imm) {return OpArg(imm, SCALE_IMM32);}
inline OpArg Imm64(u64 imm) {return OpArg(imm, SCALE_IMM64);}
#ifdef _ARCH_64
-inline OpArg ImmPtr(void* imm) {return Imm64((u64)imm);}
+inline OpArg ImmPtr(const void* imm) {return Imm64((u64)imm);}
#else
-inline OpArg ImmPtr(void* imm) {return Imm32((u32)imm);}
+inline OpArg ImmPtr(const void* imm) {return Imm32((u32)imm);}
#endif
inline u32 PtrOffset(void* ptr, void* base) {
#ifdef _ARCH_64
@@ -671,9 +672,11 @@ public:
// These will destroy the 1 or 2 first "parameter regs".
void ABI_CallFunctionC(void *func, u32 param1);
void ABI_CallFunctionCC(void *func, u32 param1, u32 param2);
+ void ABI_CallFunctionCP(void *func, u32 param1, void *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_CallFunctionPC(void *func, void *param1, u32 param2);
void ABI_CallFunctionPPC(void *func, void *param1, void *param2,u32 param3);
void ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2);
void ABI_CallFunctionA(void *func, const Gen::OpArg &arg1);
@@ -737,6 +740,26 @@ public:
#define DECLARE_IMPORT(x) extern "C" void *__imp_##x
#endif
+
+ // Utility to generate a call to a std::function object.
+ //
+ // Unfortunately, calling operator() directly is undefined behavior in C++
+ // (this method might be a thunk in the case of multi-inheritance) so we
+ // have to go through a trampoline function.
+ template <typename T, typename... Args>
+ static void CallLambdaTrampoline(const std::function<T(Args...)>* f,
+ Args... args)
+ {
+ (*f)(args...);
+ }
+
+ template <typename T, typename... Args>
+ void ABI_CallLambdaC(const std::function<T(Args...)>* f, u32 p1)
+ {
+ // Double casting is required by VC++ for some reason.
+ auto trampoline = (void(*)())&XEmitter::CallLambdaTrampoline<T, Args...>;
+ ABI_CallFunctionPC((void*)trampoline, const_cast<void*>((const void*)f), p1);
+ }
}; // class XEmitter