forked from eden-emu/eden
		
	Common: Ported over boilerplate x86 JIT code from Dolphin/PPSSPP.
This commit is contained in:
		
							parent
							
								
									4d51792285
								
							
						
					
					
						commit
						ddbeebb887
					
				
					 11 changed files with 4382 additions and 6 deletions
				
			
		|  | @ -14,7 +14,7 @@ set(HEADERS | ||||||
| create_directory_groups(${SRCS} ${HEADERS}) | create_directory_groups(${SRCS} ${HEADERS}) | ||||||
| 
 | 
 | ||||||
| add_executable(citra ${SRCS} ${HEADERS}) | add_executable(citra ${SRCS} ${HEADERS}) | ||||||
| target_link_libraries(citra core common video_core) | target_link_libraries(citra core video_core common) | ||||||
| target_link_libraries(citra ${GLFW_LIBRARIES} ${OPENGL_gl_LIBRARY} inih) | target_link_libraries(citra ${GLFW_LIBRARIES} ${OPENGL_gl_LIBRARY} inih) | ||||||
| if (MSVC) | if (MSVC) | ||||||
|     target_link_libraries(citra getopt) |     target_link_libraries(citra getopt) | ||||||
|  |  | ||||||
|  | @ -71,7 +71,7 @@ if (APPLE) | ||||||
| else() | else() | ||||||
|     add_executable(citra-qt ${SRCS} ${HEADERS} ${UI_HDRS}) |     add_executable(citra-qt ${SRCS} ${HEADERS} ${UI_HDRS}) | ||||||
| endif() | endif() | ||||||
| target_link_libraries(citra-qt core common video_core qhexedit) | target_link_libraries(citra-qt core video_core common qhexedit) | ||||||
| target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS}) | target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS}) | ||||||
| target_link_libraries(citra-qt ${PLATFORM_LIBRARIES}) | target_link_libraries(citra-qt ${PLATFORM_LIBRARIES}) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in" "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp" @ONLY) | configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in" "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp" @ONLY) | ||||||
| 
 | 
 | ||||||
| set(SRCS | set(SRCS | ||||||
|  |             abi.cpp | ||||||
|             break_points.cpp |             break_points.cpp | ||||||
|             emu_window.cpp |             emu_window.cpp | ||||||
|             file_util.cpp |             file_util.cpp | ||||||
|  | @ -20,10 +21,12 @@ set(SRCS | ||||||
|             ) |             ) | ||||||
| 
 | 
 | ||||||
| set(HEADERS | set(HEADERS | ||||||
|  |             abi.h | ||||||
|             assert.h |             assert.h | ||||||
|             bit_field.h |             bit_field.h | ||||||
|             break_points.h |             break_points.h | ||||||
|             chunk_file.h |             chunk_file.h | ||||||
|  |             code_block.h | ||||||
|             color.h |             color.h | ||||||
|             common_funcs.h |             common_funcs.h | ||||||
|             common_paths.h |             common_paths.h | ||||||
|  | @ -58,10 +61,17 @@ set(HEADERS | ||||||
| 
 | 
 | ||||||
| if(_M_X86) | if(_M_X86) | ||||||
|     set(SRCS ${SRCS} |     set(SRCS ${SRCS} | ||||||
|              cpu_detect_x86.cpp) |             cpu_detect_x86.cpp | ||||||
|  |             x64_emitter.cpp) | ||||||
|  | 
 | ||||||
|  |     set(HEADERS ${HEADERS} | ||||||
|  |             x64_emitter.h) | ||||||
| else() | else() | ||||||
|     set(SRCS ${SRCS} |     set(SRCS ${SRCS} | ||||||
|             cpu_detect_generic.cpp) |             cpu_detect_generic.cpp) | ||||||
|  | 
 | ||||||
|  |     set(HEADERS ${HEADERS} | ||||||
|  |             fake_emitter.h) | ||||||
| endif() | endif() | ||||||
| 
 | 
 | ||||||
| create_directory_groups(${SRCS} ${HEADERS}) | create_directory_groups(${SRCS} ${HEADERS}) | ||||||
|  |  | ||||||
							
								
								
									
										680
									
								
								src/common/abi.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										680
									
								
								src/common/abi.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,680 @@ | ||||||
|  | // Copyright (C) 2003 Dolphin Project.
 | ||||||
|  | 
 | ||||||
|  | // This program is free software: you can redistribute it and/or modify
 | ||||||
|  | // it under the terms of the GNU General Public License as published by
 | ||||||
|  | // the Free Software Foundation, version 2.0 or later versions.
 | ||||||
|  | 
 | ||||||
|  | // This program is distributed in the hope that it will be useful,
 | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | ||||||
|  | // GNU General Public License 2.0 for more details.
 | ||||||
|  | 
 | ||||||
|  | // A copy of the GPL 2.0 should have been included with the program.
 | ||||||
|  | // If not, see http://www.gnu.org/licenses/
 | ||||||
|  | 
 | ||||||
|  | // Official SVN repository and contact information can be found at
 | ||||||
|  | // http://code.google.com/p/dolphin-emu/
 | ||||||
|  | 
 | ||||||
|  | #include "x64_emitter.h" | ||||||
|  | #include "abi.h" | ||||||
|  | 
 | ||||||
|  | using namespace Gen; | ||||||
|  | 
 | ||||||
|  | // Shared code between Win64 and Unix64
 | ||||||
|  | 
 | ||||||
|  | // Sets up a __cdecl function.
 | ||||||
|  | void XEmitter::ABI_EmitPrologue(int maxCallParams) | ||||||
|  | { | ||||||
|  | #ifdef _M_IX86 | ||||||
|  |     // Don't really need to do anything
 | ||||||
|  | #elif defined(_M_X86_64) | ||||||
|  | #if _WIN32 | ||||||
|  |     int stacksize = ((maxCallParams + 1) & ~1) * 8 + 8; | ||||||
|  |     // Set up a stack frame so that we can call functions
 | ||||||
|  |     // TODO: use maxCallParams
 | ||||||
|  |     SUB(64, R(RSP), Imm8(stacksize)); | ||||||
|  | #endif | ||||||
|  | #else | ||||||
|  | #error Arch not supported | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_EmitEpilogue(int maxCallParams) | ||||||
|  | { | ||||||
|  | #ifdef _M_IX86 | ||||||
|  |     RET(); | ||||||
|  | #elif defined(_M_X86_64) | ||||||
|  | #ifdef _WIN32 | ||||||
|  |     int stacksize = ((maxCallParams+1)&~1)*8 + 8; | ||||||
|  |     ADD(64, R(RSP), Imm8(stacksize)); | ||||||
|  | #endif | ||||||
|  |     RET(); | ||||||
|  | #else | ||||||
|  | #error Arch not supported | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #ifdef _M_IX86 // All32
 | ||||||
|  | 
 | ||||||
|  | // Shared code between Win32 and Unix32
 | ||||||
|  | void XEmitter::ABI_CallFunction(const void *func) { | ||||||
|  |     ABI_AlignStack(0); | ||||||
|  |     CALL(func); | ||||||
|  |     ABI_RestoreStack(0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionC16(const void *func, u16 param1) { | ||||||
|  |     ABI_AlignStack(1 * 2); | ||||||
|  |     PUSH(16, Imm16(param1)); | ||||||
|  |     CALL(func); | ||||||
|  |     ABI_RestoreStack(1 * 2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionCC16(const void *func, u32 param1, u16 param2) { | ||||||
|  |     ABI_AlignStack(1 * 2 + 1 * 4); | ||||||
|  |     PUSH(16, Imm16(param2)); | ||||||
|  |     PUSH(32, Imm32(param1)); | ||||||
|  |     CALL(func); | ||||||
|  |     ABI_RestoreStack(1 * 2 + 1 * 4); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionC(const void *func, u32 param1) { | ||||||
|  |     ABI_AlignStack(1 * 4); | ||||||
|  |     PUSH(32, Imm32(param1)); | ||||||
|  |     CALL(func); | ||||||
|  |     ABI_RestoreStack(1 * 4); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionCC(const void *func, u32 param1, u32 param2) { | ||||||
|  |     ABI_AlignStack(2 * 4); | ||||||
|  |     PUSH(32, Imm32(param2)); | ||||||
|  |     PUSH(32, Imm32(param1)); | ||||||
|  |     CALL(func); | ||||||
|  |     ABI_RestoreStack(2 * 4); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionCCC(const void *func, u32 param1, u32 param2, u32 param3) { | ||||||
|  |     ABI_AlignStack(3 * 4); | ||||||
|  |     PUSH(32, Imm32(param3)); | ||||||
|  |     PUSH(32, Imm32(param2)); | ||||||
|  |     PUSH(32, Imm32(param1)); | ||||||
|  |     CALL(func); | ||||||
|  |     ABI_RestoreStack(3 * 4); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionCCP(const void *func, u32 param1, u32 param2, void *param3) { | ||||||
|  |     ABI_AlignStack(3 * 4); | ||||||
|  |     PUSH(32, ImmPtr(param3)); | ||||||
|  |     PUSH(32, Imm32(param2)); | ||||||
|  |     PUSH(32, Imm32(param1)); | ||||||
|  |     CALL(func); | ||||||
|  |     ABI_RestoreStack(3 * 4); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionCCCP(const void *func, u32 param1, u32 param2,u32 param3, void *param4) { | ||||||
|  |     ABI_AlignStack(4 * 4); | ||||||
|  |     PUSH(32, ImmPtr(param4)); | ||||||
|  |     PUSH(32, Imm32(param3)); | ||||||
|  |     PUSH(32, Imm32(param2)); | ||||||
|  |     PUSH(32, Imm32(param1)); | ||||||
|  |     CALL(func); | ||||||
|  |     ABI_RestoreStack(4 * 4); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionP(const void *func, void *param1) { | ||||||
|  |     ABI_AlignStack(1 * 4); | ||||||
|  |     PUSH(32, ImmPtr(param1)); | ||||||
|  |     CALL(func); | ||||||
|  |     ABI_RestoreStack(1 * 4); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionPA(const void *func, void *param1, const Gen::OpArg &arg2) { | ||||||
|  |     ABI_AlignStack(2 * 4); | ||||||
|  |     PUSH(32, arg2); | ||||||
|  |     PUSH(32, ImmPtr(param1)); | ||||||
|  |     CALL(func); | ||||||
|  |     ABI_RestoreStack(2 * 4); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionPAA(const void *func, void *param1, const Gen::OpArg &arg2, const Gen::OpArg &arg3) { | ||||||
|  |     ABI_AlignStack(3 * 4); | ||||||
|  |     PUSH(32, arg3); | ||||||
|  |     PUSH(32, arg2); | ||||||
|  |     PUSH(32, ImmPtr(param1)); | ||||||
|  |     CALL(func); | ||||||
|  |     ABI_RestoreStack(3 * 4); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionPPC(const void *func, void *param1, void *param2, u32 param3) { | ||||||
|  |     ABI_AlignStack(3 * 4); | ||||||
|  |     PUSH(32, Imm32(param3)); | ||||||
|  |     PUSH(32, ImmPtr(param2)); | ||||||
|  |     PUSH(32, ImmPtr(param1)); | ||||||
|  |     CALL(func); | ||||||
|  |     ABI_RestoreStack(3 * 4); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Pass a register as a parameter.
 | ||||||
|  | void XEmitter::ABI_CallFunctionR(const void *func, X64Reg reg1) { | ||||||
|  |     ABI_AlignStack(1 * 4); | ||||||
|  |     PUSH(32, R(reg1)); | ||||||
|  |     CALL(func); | ||||||
|  |     ABI_RestoreStack(1 * 4); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Pass two registers as parameters.
 | ||||||
|  | void XEmitter::ABI_CallFunctionRR(const void *func, Gen::X64Reg reg1, Gen::X64Reg reg2) | ||||||
|  | { | ||||||
|  |     ABI_AlignStack(2 * 4); | ||||||
|  |     PUSH(32, R(reg2)); | ||||||
|  |     PUSH(32, R(reg1)); | ||||||
|  |     CALL(func); | ||||||
|  |     ABI_RestoreStack(2 * 4); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionAC(const void *func, const Gen::OpArg &arg1, u32 param2) | ||||||
|  | { | ||||||
|  |     ABI_AlignStack(2 * 4); | ||||||
|  |     PUSH(32, Imm32(param2)); | ||||||
|  |     PUSH(32, arg1); | ||||||
|  |     CALL(func); | ||||||
|  |     ABI_RestoreStack(2 * 4); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionACC(const void *func, const Gen::OpArg &arg1, u32 param2, u32 param3) | ||||||
|  | { | ||||||
|  |     ABI_AlignStack(3 * 4); | ||||||
|  |     PUSH(32, Imm32(param3)); | ||||||
|  |     PUSH(32, Imm32(param2)); | ||||||
|  |     PUSH(32, arg1); | ||||||
|  |     CALL(func); | ||||||
|  |     ABI_RestoreStack(3 * 4); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionA(const void *func, const Gen::OpArg &arg1) | ||||||
|  | { | ||||||
|  |     ABI_AlignStack(1 * 4); | ||||||
|  |     PUSH(32, arg1); | ||||||
|  |     CALL(func); | ||||||
|  |     ABI_RestoreStack(1 * 4); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionAA(const void *func, const Gen::OpArg &arg1, const Gen::OpArg &arg2) | ||||||
|  | { | ||||||
|  |     ABI_AlignStack(2 * 4); | ||||||
|  |     PUSH(32, arg2); | ||||||
|  |     PUSH(32, arg1); | ||||||
|  |     CALL(func); | ||||||
|  |     ABI_RestoreStack(2 * 4); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_PushAllCalleeSavedRegsAndAdjustStack() { | ||||||
|  |     // Note: 4 * 4 = 16 bytes, so alignment is preserved.
 | ||||||
|  |     PUSH(EBP); | ||||||
|  |     PUSH(EBX); | ||||||
|  |     PUSH(ESI); | ||||||
|  |     PUSH(EDI); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_PopAllCalleeSavedRegsAndAdjustStack() { | ||||||
|  |     POP(EDI); | ||||||
|  |     POP(ESI); | ||||||
|  |     POP(EBX); | ||||||
|  |     POP(EBP); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | unsigned int XEmitter::ABI_GetAlignedFrameSize(unsigned int frameSize) { | ||||||
|  |     frameSize += 4; // reserve space for return address
 | ||||||
|  |     unsigned int alignedSize = | ||||||
|  | #ifdef __GNUC__ | ||||||
|  |         (frameSize + 15) & -16; | ||||||
|  | #else | ||||||
|  |         (frameSize + 3) & -4; | ||||||
|  | #endif | ||||||
|  |     return alignedSize; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_AlignStack(unsigned int frameSize) { | ||||||
|  | // Mac OS X requires the stack to be 16-byte aligned before every call.
 | ||||||
|  | // Linux requires the stack to be 16-byte aligned before calls that put SSE
 | ||||||
|  | // vectors on the stack, but since we do not keep track of which calls do that,
 | ||||||
|  | // it is effectively every call as well.
 | ||||||
|  | // Windows binaries compiled with MSVC do not have such a restriction*, but I
 | ||||||
|  | // expect that GCC on Windows acts the same as GCC on Linux in this respect.
 | ||||||
|  | // It would be nice if someone could verify this.
 | ||||||
|  | // *However, the MSVC optimizing compiler assumes a 4-byte-aligned stack at times.
 | ||||||
|  |     unsigned int fillSize = | ||||||
|  |         ABI_GetAlignedFrameSize(frameSize) - (frameSize + 4); | ||||||
|  |     if (fillSize != 0) { | ||||||
|  |         SUB(32, R(ESP), Imm8(fillSize)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_RestoreStack(unsigned int frameSize) { | ||||||
|  |     unsigned int alignedSize = ABI_GetAlignedFrameSize(frameSize); | ||||||
|  |     alignedSize -= 4; // return address is POPped at end of call
 | ||||||
|  |     if (alignedSize != 0) { | ||||||
|  |         ADD(32, R(ESP), Imm8(alignedSize)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #else //64bit
 | ||||||
|  | 
 | ||||||
|  | // Common functions
 | ||||||
|  | void XEmitter::ABI_CallFunction(const void *func) { | ||||||
|  |     u64 distance = u64(func) - (u64(code) + 5); | ||||||
|  |     if (distance >= 0x0000000080000000ULL | ||||||
|  |      && distance <  0xFFFFFFFF80000000ULL) { | ||||||
|  |         // Far call
 | ||||||
|  |         MOV(64, R(RAX), ImmPtr(func)); | ||||||
|  |         CALLptr(R(RAX)); | ||||||
|  |     } else { | ||||||
|  |         CALL(func); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionC16(const void *func, u16 param1) { | ||||||
|  |     MOV(32, R(ABI_PARAM1), Imm32((u32)param1)); | ||||||
|  |     u64 distance = u64(func) - (u64(code) + 5); | ||||||
|  |     if (distance >= 0x0000000080000000ULL | ||||||
|  |      && distance <  0xFFFFFFFF80000000ULL) { | ||||||
|  |         // Far call
 | ||||||
|  |         MOV(64, R(RAX), ImmPtr(func)); | ||||||
|  |         CALLptr(R(RAX)); | ||||||
|  |     } else { | ||||||
|  |         CALL(func); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionCC16(const void *func, u32 param1, u16 param2) { | ||||||
|  |     MOV(32, R(ABI_PARAM1), Imm32(param1)); | ||||||
|  |     MOV(32, R(ABI_PARAM2), Imm32((u32)param2)); | ||||||
|  |     u64 distance = u64(func) - (u64(code) + 5); | ||||||
|  |     if (distance >= 0x0000000080000000ULL | ||||||
|  |         && distance <  0xFFFFFFFF80000000ULL) { | ||||||
|  |             // Far call
 | ||||||
|  |             MOV(64, R(RAX), ImmPtr(func)); | ||||||
|  |             CALLptr(R(RAX)); | ||||||
|  |     } else { | ||||||
|  |         CALL(func); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionC(const void *func, u32 param1) { | ||||||
|  |     MOV(32, R(ABI_PARAM1), Imm32(param1)); | ||||||
|  |     u64 distance = u64(func) - (u64(code) + 5); | ||||||
|  |     if (distance >= 0x0000000080000000ULL | ||||||
|  |      && distance <  0xFFFFFFFF80000000ULL) { | ||||||
|  |         // Far call
 | ||||||
|  |         MOV(64, R(RAX), ImmPtr(func)); | ||||||
|  |         CALLptr(R(RAX)); | ||||||
|  |     } else { | ||||||
|  |         CALL(func); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionCC(const void *func, u32 param1, u32 param2) { | ||||||
|  |     MOV(32, R(ABI_PARAM1), Imm32(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), ImmPtr(func)); | ||||||
|  |         CALLptr(R(RAX)); | ||||||
|  |     } else { | ||||||
|  |         CALL(func); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionCCC(const void *func, u32 param1, u32 param2, u32 param3) { | ||||||
|  |     MOV(32, R(ABI_PARAM1), Imm32(param1)); | ||||||
|  |     MOV(32, R(ABI_PARAM2), Imm32(param2)); | ||||||
|  |     MOV(32, R(ABI_PARAM3), Imm32(param3)); | ||||||
|  |     u64 distance = u64(func) - (u64(code) + 5); | ||||||
|  |     if (distance >= 0x0000000080000000ULL | ||||||
|  |      && distance <  0xFFFFFFFF80000000ULL) { | ||||||
|  |         // Far call
 | ||||||
|  |         MOV(64, R(RAX), ImmPtr(func)); | ||||||
|  |         CALLptr(R(RAX)); | ||||||
|  |     } else { | ||||||
|  |         CALL(func); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionCCP(const void *func, u32 param1, u32 param2, void *param3) { | ||||||
|  |     MOV(32, R(ABI_PARAM1), Imm32(param1)); | ||||||
|  |     MOV(32, R(ABI_PARAM2), Imm32(param2)); | ||||||
|  |     MOV(64, R(ABI_PARAM3), ImmPtr(param3)); | ||||||
|  |     u64 distance = u64(func) - (u64(code) + 5); | ||||||
|  |     if (distance >= 0x0000000080000000ULL | ||||||
|  |      && distance <  0xFFFFFFFF80000000ULL) { | ||||||
|  |         // Far call
 | ||||||
|  |         MOV(64, R(RAX), ImmPtr(func)); | ||||||
|  |         CALLptr(R(RAX)); | ||||||
|  |     } else { | ||||||
|  |         CALL(func); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionCCCP(const void *func, u32 param1, u32 param2, u32 param3, void *param4) { | ||||||
|  |     MOV(32, R(ABI_PARAM1), Imm32(param1)); | ||||||
|  |     MOV(32, R(ABI_PARAM2), Imm32(param2)); | ||||||
|  |     MOV(32, R(ABI_PARAM3), Imm32(param3)); | ||||||
|  |     MOV(64, R(ABI_PARAM4), ImmPtr(param4)); | ||||||
|  |     u64 distance = u64(func) - (u64(code) + 5); | ||||||
|  |     if (distance >= 0x0000000080000000ULL | ||||||
|  |      && distance <  0xFFFFFFFF80000000ULL) { | ||||||
|  |         // Far call
 | ||||||
|  |         MOV(64, R(RAX), ImmPtr(func)); | ||||||
|  |         CALLptr(R(RAX)); | ||||||
|  |     } else { | ||||||
|  |         CALL(func); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionP(const void *func, void *param1) { | ||||||
|  |     MOV(64, R(ABI_PARAM1), ImmPtr(param1)); | ||||||
|  |     u64 distance = u64(func) - (u64(code) + 5); | ||||||
|  |     if (distance >= 0x0000000080000000ULL | ||||||
|  |      && distance <  0xFFFFFFFF80000000ULL) { | ||||||
|  |         // Far call
 | ||||||
|  |         MOV(64, R(RAX), ImmPtr(func)); | ||||||
|  |         CALLptr(R(RAX)); | ||||||
|  |     } else { | ||||||
|  |         CALL(func); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionPA(const void *func, void *param1, const Gen::OpArg &arg2) { | ||||||
|  |     MOV(64, R(ABI_PARAM1), ImmPtr(param1)); | ||||||
|  |     if (!arg2.IsSimpleReg(ABI_PARAM2)) | ||||||
|  |         MOV(32, R(ABI_PARAM2), arg2); | ||||||
|  |     u64 distance = u64(func) - (u64(code) + 5); | ||||||
|  |     if (distance >= 0x0000000080000000ULL | ||||||
|  |      && distance <  0xFFFFFFFF80000000ULL) { | ||||||
|  |         // Far call
 | ||||||
|  |         MOV(64, R(RAX), ImmPtr(func)); | ||||||
|  |         CALLptr(R(RAX)); | ||||||
|  |     } else { | ||||||
|  |         CALL(func); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionPAA(const void *func, void *param1, const Gen::OpArg &arg2, const Gen::OpArg &arg3) { | ||||||
|  |     MOV(64, R(ABI_PARAM1), ImmPtr(param1)); | ||||||
|  |     if (!arg2.IsSimpleReg(ABI_PARAM2)) | ||||||
|  |         MOV(32, R(ABI_PARAM2), arg2); | ||||||
|  |     if (!arg3.IsSimpleReg(ABI_PARAM3)) | ||||||
|  |         MOV(32, R(ABI_PARAM3), arg3); | ||||||
|  |     u64 distance = u64(func) - (u64(code) + 5); | ||||||
|  |     if (distance >= 0x0000000080000000ULL | ||||||
|  |      && distance <  0xFFFFFFFF80000000ULL) { | ||||||
|  |         // Far call
 | ||||||
|  |         MOV(64, R(RAX), ImmPtr(func)); | ||||||
|  |         CALLptr(R(RAX)); | ||||||
|  |     } else { | ||||||
|  |         CALL(func); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionPPC(const void *func, void *param1, void *param2, u32 param3) { | ||||||
|  |     MOV(64, R(ABI_PARAM1), ImmPtr(param1)); | ||||||
|  |     MOV(64, R(ABI_PARAM2), ImmPtr(param2)); | ||||||
|  |     MOV(32, R(ABI_PARAM3), Imm32(param3)); | ||||||
|  |     u64 distance = u64(func) - (u64(code) + 5); | ||||||
|  |     if (distance >= 0x0000000080000000ULL | ||||||
|  |      && distance <  0xFFFFFFFF80000000ULL) { | ||||||
|  |         // Far call
 | ||||||
|  |         MOV(64, R(RAX), ImmPtr(func)); | ||||||
|  |         CALLptr(R(RAX)); | ||||||
|  |     } else { | ||||||
|  |         CALL(func); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 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)); | ||||||
|  |     u64 distance = u64(func) - (u64(code) + 5); | ||||||
|  |     if (distance >= 0x0000000080000000ULL | ||||||
|  |      && distance <  0xFFFFFFFF80000000ULL) { | ||||||
|  |         // Far call
 | ||||||
|  |         MOV(64, R(RAX), ImmPtr(func)); | ||||||
|  |         CALLptr(R(RAX)); | ||||||
|  |     } else { | ||||||
|  |         CALL(func); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Pass two registers as parameters.
 | ||||||
|  | void XEmitter::ABI_CallFunctionRR(const void *func, X64Reg reg1, X64Reg reg2) { | ||||||
|  |     if (reg2 != ABI_PARAM1) { | ||||||
|  |         if (reg1 != ABI_PARAM1) | ||||||
|  |             MOV(64, R(ABI_PARAM1), R(reg1)); | ||||||
|  |         if (reg2 != ABI_PARAM2) | ||||||
|  |             MOV(64, R(ABI_PARAM2), R(reg2)); | ||||||
|  |     } else { | ||||||
|  |         if (reg2 != ABI_PARAM2) | ||||||
|  |             MOV(64, R(ABI_PARAM2), R(reg2)); | ||||||
|  |         if (reg1 != ABI_PARAM1) | ||||||
|  |             MOV(64, R(ABI_PARAM1), R(reg1)); | ||||||
|  |     } | ||||||
|  |     u64 distance = u64(func) - (u64(code) + 5); | ||||||
|  |     if (distance >= 0x0000000080000000ULL | ||||||
|  |      && distance <  0xFFFFFFFF80000000ULL) { | ||||||
|  |         // Far call
 | ||||||
|  |         MOV(64, R(RAX), ImmPtr(func)); | ||||||
|  |         CALLptr(R(RAX)); | ||||||
|  |     } else { | ||||||
|  |         CALL(func); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionAC(const void *func, const Gen::OpArg &arg1, u32 param2) | ||||||
|  | { | ||||||
|  |     if (!arg1.IsSimpleReg(ABI_PARAM1)) | ||||||
|  |         MOV(32, R(ABI_PARAM1), arg1); | ||||||
|  |     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), ImmPtr(func)); | ||||||
|  |         CALLptr(R(RAX)); | ||||||
|  |     } else { | ||||||
|  |         CALL(func); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionACC(const void *func, const Gen::OpArg &arg1, u32 param2, u32 param3) | ||||||
|  | { | ||||||
|  |     if (!arg1.IsSimpleReg(ABI_PARAM1)) | ||||||
|  |         MOV(32, R(ABI_PARAM1), arg1); | ||||||
|  |     MOV(32, R(ABI_PARAM2), Imm32(param2)); | ||||||
|  |     MOV(64, R(ABI_PARAM3), Imm64(param3)); | ||||||
|  |     u64 distance = u64(func) - (u64(code) + 5); | ||||||
|  |     if (distance >= 0x0000000080000000ULL | ||||||
|  |      && distance <  0xFFFFFFFF80000000ULL) { | ||||||
|  |         // Far call
 | ||||||
|  |         MOV(64, R(RAX), ImmPtr(func)); | ||||||
|  |         CALLptr(R(RAX)); | ||||||
|  |     } else { | ||||||
|  |         CALL(func); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionA(const void *func, const Gen::OpArg &arg1) | ||||||
|  | { | ||||||
|  |     if (!arg1.IsSimpleReg(ABI_PARAM1)) | ||||||
|  |         MOV(32, R(ABI_PARAM1), arg1); | ||||||
|  |     u64 distance = u64(func) - (u64(code) + 5); | ||||||
|  |     if (distance >= 0x0000000080000000ULL | ||||||
|  |      && distance <  0xFFFFFFFF80000000ULL) { | ||||||
|  |         // Far call
 | ||||||
|  |         MOV(64, R(RAX), ImmPtr(func)); | ||||||
|  |         CALLptr(R(RAX)); | ||||||
|  |     } else { | ||||||
|  |         CALL(func); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_CallFunctionAA(const void *func, const Gen::OpArg &arg1, const Gen::OpArg &arg2) | ||||||
|  | { | ||||||
|  |     if (!arg1.IsSimpleReg(ABI_PARAM1)) | ||||||
|  |         MOV(32, R(ABI_PARAM1), arg1); | ||||||
|  |     if (!arg2.IsSimpleReg(ABI_PARAM2)) | ||||||
|  |         MOV(32, R(ABI_PARAM2), arg2); | ||||||
|  |     u64 distance = u64(func) - (u64(code) + 5); | ||||||
|  |     if (distance >= 0x0000000080000000ULL | ||||||
|  |      && distance <  0xFFFFFFFF80000000ULL) { | ||||||
|  |         // Far call
 | ||||||
|  |         MOV(64, R(RAX), ImmPtr(func)); | ||||||
|  |         CALLptr(R(RAX)); | ||||||
|  |     } else { | ||||||
|  |         CALL(func); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | unsigned int XEmitter::ABI_GetAlignedFrameSize(unsigned int frameSize) { | ||||||
|  |     return frameSize; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #ifdef _WIN32 | ||||||
|  | 
 | ||||||
|  | // The Windows x64 ABI requires XMM6 - XMM15 to be callee saved.  10 regs.
 | ||||||
|  | // But, not saving XMM4 and XMM5 breaks things in VS 2010, even though they are volatile regs.
 | ||||||
|  | // Let's just save all 16.
 | ||||||
|  | const int XMM_STACK_SPACE = 16 * 16; | ||||||
|  | 
 | ||||||
|  | // Win64 Specific Code
 | ||||||
|  | void XEmitter::ABI_PushAllCalleeSavedRegsAndAdjustStack() { | ||||||
|  |     //we only want to do this once
 | ||||||
|  |     PUSH(RBX); | ||||||
|  |     PUSH(RSI); | ||||||
|  |     PUSH(RDI); | ||||||
|  |     PUSH(RBP); | ||||||
|  |     PUSH(R12); | ||||||
|  |     PUSH(R13); | ||||||
|  |     PUSH(R14); | ||||||
|  |     PUSH(R15); | ||||||
|  |     ABI_AlignStack(0); | ||||||
|  | 
 | ||||||
|  |     // Do this after aligning, because before it's offset by 8.
 | ||||||
|  |     SUB(64, R(RSP), Imm32(XMM_STACK_SPACE)); | ||||||
|  |     for (int i = 0; i < 16; ++i) | ||||||
|  |         MOVAPS(MDisp(RSP, i * 16), (X64Reg)(XMM0 + i)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_PopAllCalleeSavedRegsAndAdjustStack() { | ||||||
|  |     for (int i = 0; i < 16; ++i) | ||||||
|  |         MOVAPS((X64Reg)(XMM0 + i), MDisp(RSP, i * 16)); | ||||||
|  |     ADD(64, R(RSP), Imm32(XMM_STACK_SPACE)); | ||||||
|  | 
 | ||||||
|  |     ABI_RestoreStack(0); | ||||||
|  |     POP(R15); | ||||||
|  |     POP(R14); | ||||||
|  |     POP(R13); | ||||||
|  |     POP(R12); | ||||||
|  |     POP(RBP); | ||||||
|  |     POP(RDI); | ||||||
|  |     POP(RSI); | ||||||
|  |     POP(RBX); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Win64 Specific Code
 | ||||||
|  | void XEmitter::ABI_PushAllCallerSavedRegsAndAdjustStack() { | ||||||
|  |     PUSH(RCX); | ||||||
|  |     PUSH(RDX); | ||||||
|  |     PUSH(RSI); | ||||||
|  |     PUSH(RDI); | ||||||
|  |     PUSH(R8); | ||||||
|  |     PUSH(R9); | ||||||
|  |     PUSH(R10); | ||||||
|  |     PUSH(R11); | ||||||
|  |     // TODO: Callers preserve XMM4-5 (XMM0-3 are args.)
 | ||||||
|  |     ABI_AlignStack(0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_PopAllCallerSavedRegsAndAdjustStack() { | ||||||
|  |     ABI_RestoreStack(0); | ||||||
|  |     POP(R11); | ||||||
|  |     POP(R10); | ||||||
|  |     POP(R9); | ||||||
|  |     POP(R8); | ||||||
|  |     POP(RDI); | ||||||
|  |     POP(RSI); | ||||||
|  |     POP(RDX); | ||||||
|  |     POP(RCX); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_AlignStack(unsigned int /*frameSize*/) { | ||||||
|  |     SUB(64, R(RSP), Imm8(0x28)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_RestoreStack(unsigned int /*frameSize*/) { | ||||||
|  |     ADD(64, R(RSP), Imm8(0x28)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #else | ||||||
|  | // Unix64 Specific Code
 | ||||||
|  | void XEmitter::ABI_PushAllCalleeSavedRegsAndAdjustStack() { | ||||||
|  |     PUSH(RBX); | ||||||
|  |     PUSH(RBP); | ||||||
|  |     PUSH(R12); | ||||||
|  |     PUSH(R13); | ||||||
|  |     PUSH(R14); | ||||||
|  |     PUSH(R15); | ||||||
|  |     PUSH(R15); //just to align stack. duped push/pop doesn't hurt.
 | ||||||
|  |     // TODO: XMM?
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_PopAllCalleeSavedRegsAndAdjustStack() { | ||||||
|  |     POP(R15); | ||||||
|  |     POP(R15); | ||||||
|  |     POP(R14); | ||||||
|  |     POP(R13); | ||||||
|  |     POP(R12); | ||||||
|  |     POP(RBP); | ||||||
|  |     POP(RBX); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_PushAllCallerSavedRegsAndAdjustStack() { | ||||||
|  |     PUSH(RCX); | ||||||
|  |     PUSH(RDX); | ||||||
|  |     PUSH(RSI); | ||||||
|  |     PUSH(RDI); | ||||||
|  |     PUSH(R8); | ||||||
|  |     PUSH(R9); | ||||||
|  |     PUSH(R10); | ||||||
|  |     PUSH(R11); | ||||||
|  |     PUSH(R11); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_PopAllCallerSavedRegsAndAdjustStack() { | ||||||
|  |     POP(R11); | ||||||
|  |     POP(R11); | ||||||
|  |     POP(R10); | ||||||
|  |     POP(R9); | ||||||
|  |     POP(R8); | ||||||
|  |     POP(RDI); | ||||||
|  |     POP(RSI); | ||||||
|  |     POP(RDX); | ||||||
|  |     POP(RCX); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_AlignStack(unsigned int /*frameSize*/) { | ||||||
|  |     SUB(64, R(RSP), Imm8(0x08)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void XEmitter::ABI_RestoreStack(unsigned int /*frameSize*/) { | ||||||
|  |     ADD(64, R(RSP), Imm8(0x08)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif // WIN32
 | ||||||
|  | 
 | ||||||
|  | #endif // 32bit
 | ||||||
							
								
								
									
										78
									
								
								src/common/abi.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/common/abi.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,78 @@ | ||||||
|  | // Copyright (C) 2003 Dolphin Project.
 | ||||||
|  | 
 | ||||||
|  | // This program is free software: you can redistribute it and/or modify
 | ||||||
|  | // it under the terms of the GNU General Public License as published by
 | ||||||
|  | // the Free Software Foundation, version 2.0 or later versions.
 | ||||||
|  | 
 | ||||||
|  | // This program is distributed in the hope that it will be useful,
 | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | ||||||
|  | // GNU General Public License 2.0 for more details.
 | ||||||
|  | 
 | ||||||
|  | // A copy of the GPL 2.0 should have been included with the program.
 | ||||||
|  | // If not, see http://www.gnu.org/licenses/
 | ||||||
|  | 
 | ||||||
|  | // Official SVN repository and contact information can be found at
 | ||||||
|  | // http://code.google.com/p/dolphin-emu/
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "common_types.h" | ||||||
|  | 
 | ||||||
|  | // x86/x64 ABI:s, and helpers to help follow them when JIT-ing code.
 | ||||||
|  | // All convensions return values in EAX (+ possibly EDX).
 | ||||||
|  | 
 | ||||||
|  | // Linux 32-bit, Windows 32-bit (cdecl, System V):
 | ||||||
|  | // * Caller pushes left to right
 | ||||||
|  | // * Caller fixes stack after call
 | ||||||
|  | // * function subtract from stack for local storage only.
 | ||||||
|  | // Scratch:      EAX ECX EDX
 | ||||||
|  | // Callee-save:  EBX ESI EDI EBP
 | ||||||
|  | // Parameters:   -
 | ||||||
|  | 
 | ||||||
|  | // Windows 64-bit
 | ||||||
|  | // * 4-reg "fastcall" variant, very new-skool stack handling
 | ||||||
|  | // * Callee moves stack pointer, to make room for shadow regs for the biggest function _it itself calls_
 | ||||||
|  | // * Parameters passed in RCX, RDX, ... further parameters are MOVed into the allocated stack space.
 | ||||||
|  | // Scratch:      RAX RCX RDX R8 R9 R10 R11
 | ||||||
|  | // Callee-save:  RBX RSI RDI RBP R12 R13 R14 R15
 | ||||||
|  | // Parameters:   RCX RDX R8 R9, further MOV-ed
 | ||||||
|  | 
 | ||||||
|  | // Linux 64-bit
 | ||||||
|  | // * 6-reg "fastcall" variant, old skool stack handling (parameters are pushed)
 | ||||||
|  | // Scratch:      RAX RCX RDX RSI RDI R8 R9 R10 R11
 | ||||||
|  | // Callee-save:  RBX RBP R12 R13 R14 R15
 | ||||||
|  | // Parameters:   RDI RSI RDX RCX R8 R9
 | ||||||
|  | 
 | ||||||
|  | #ifdef _M_IX86 // 32 bit calling convention, shared by all
 | ||||||
|  | 
 | ||||||
|  | // 32-bit don't pass parameters in regs, but these are convenient to have anyway when we have to
 | ||||||
|  | // choose regs to put stuff in.
 | ||||||
|  | #define ABI_PARAM1 RCX | ||||||
|  | #define ABI_PARAM2 RDX | ||||||
|  | 
 | ||||||
|  | // There are no ABI_PARAM* here, since args are pushed.
 | ||||||
|  | // 32-bit bog standard cdecl, shared between linux and windows
 | ||||||
|  | // MacOSX 32-bit is same as System V with a few exceptions that we probably don't care much about.
 | ||||||
|  | 
 | ||||||
|  | #elif _M_X86_64 // 64 bit calling convention
 | ||||||
|  | 
 | ||||||
|  | #ifdef _WIN32 // 64-bit Windows - the really exotic calling convention
 | ||||||
|  | 
 | ||||||
|  | #define ABI_PARAM1 RCX | ||||||
|  | #define ABI_PARAM2 RDX | ||||||
|  | #define ABI_PARAM3 R8 | ||||||
|  | #define ABI_PARAM4 R9 | ||||||
|  | 
 | ||||||
|  | #else  //64-bit Unix (hopefully MacOSX too)
 | ||||||
|  | 
 | ||||||
|  | #define ABI_PARAM1 RDI | ||||||
|  | #define ABI_PARAM2 RSI | ||||||
|  | #define ABI_PARAM3 RDX | ||||||
|  | #define ABI_PARAM4 RCX | ||||||
|  | #define ABI_PARAM5 R8 | ||||||
|  | #define ABI_PARAM6 R9 | ||||||
|  | 
 | ||||||
|  | #endif // WIN32
 | ||||||
|  | 
 | ||||||
|  | #endif // X86
 | ||||||
							
								
								
									
										87
									
								
								src/common/code_block.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/common/code_block.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,87 @@ | ||||||
|  | // Copyright 2013 Dolphin Emulator Project
 | ||||||
|  | // Licensed under GPLv2
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "common_types.h" | ||||||
|  | #include "memory_util.h" | ||||||
|  | 
 | ||||||
|  | // Everything that needs to generate code should inherit from this.
 | ||||||
|  | // You get memory management for free, plus, you can use all emitter functions without
 | ||||||
|  | // having to prefix them with gen-> or something similar.
 | ||||||
|  | // Example implementation:
 | ||||||
|  | // class JIT : public CodeBlock<ARMXEmitter> {}
 | ||||||
|  | template<class T> class CodeBlock : public T, NonCopyable | ||||||
|  | { | ||||||
|  | private: | ||||||
|  |     // A privately used function to set the executable RAM space to something invalid.
 | ||||||
|  |     // For debugging usefulness it should be used to set the RAM to a host specific breakpoint instruction
 | ||||||
|  |     virtual void PoisonMemory() = 0; | ||||||
|  | 
 | ||||||
|  | protected: | ||||||
|  |     u8 *region; | ||||||
|  |     size_t region_size; | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  |     CodeBlock() : region(nullptr), region_size(0) {} | ||||||
|  |     virtual ~CodeBlock() { if (region) FreeCodeSpace(); } | ||||||
|  | 
 | ||||||
|  |     // Call this before you generate any code.
 | ||||||
|  |     void AllocCodeSpace(int size) | ||||||
|  |     { | ||||||
|  |         region_size = size; | ||||||
|  |         region = (u8*)AllocateExecutableMemory(region_size); | ||||||
|  |         T::SetCodePtr(region); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Always clear code space with breakpoints, so that if someone accidentally executes
 | ||||||
|  |     // uninitialized, it just breaks into the debugger.
 | ||||||
|  |     void ClearCodeSpace() | ||||||
|  |     { | ||||||
|  |         PoisonMemory(); | ||||||
|  |         ResetCodePtr(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Call this when shutting down. Don't rely on the destructor, even though it'll do the job.
 | ||||||
|  |     void FreeCodeSpace() | ||||||
|  |     { | ||||||
|  | #ifdef __SYMBIAN32__ | ||||||
|  |         ResetExecutableMemory(region); | ||||||
|  | #else | ||||||
|  |         FreeMemoryPages(region, region_size); | ||||||
|  | #endif | ||||||
|  |         region = nullptr; | ||||||
|  |         region_size = 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool IsInSpace(const u8 *ptr) | ||||||
|  |     { | ||||||
|  |         return (ptr >= region) && (ptr < (region + region_size)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Cannot currently be undone. Will write protect the entire code region.
 | ||||||
|  |     // Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()).
 | ||||||
|  |     void WriteProtect() | ||||||
|  |     { | ||||||
|  |         WriteProtectMemory(region, region_size, true); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void ResetCodePtr() | ||||||
|  |     { | ||||||
|  |         T::SetCodePtr(region); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     size_t GetSpaceLeft() const | ||||||
|  |     { | ||||||
|  |         return region_size - (T::GetCodePtr() - region); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     u8 *GetBasePtr() { | ||||||
|  |         return region; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     size_t GetOffset(const u8 *ptr) const { | ||||||
|  |         return ptr - region; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | @ -35,7 +35,7 @@ | ||||||
| 
 | 
 | ||||||
| #ifndef _MSC_VER | #ifndef _MSC_VER | ||||||
| 
 | 
 | ||||||
| #if defined(__x86_64__) || defined(_M_X64) | #if defined(__x86_64__) || defined(_M_X86_64) | ||||||
| #define Crash() __asm__ __volatile__("int $3") | #define Crash() __asm__ __volatile__("int $3") | ||||||
| #elif defined(_M_ARM) | #elif defined(_M_ARM) | ||||||
| #define Crash() __asm__ __volatile__("trap") | #define Crash() __asm__ __volatile__("trap") | ||||||
|  |  | ||||||
							
								
								
									
										465
									
								
								src/common/fake_emitter.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										465
									
								
								src/common/fake_emitter.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,465 @@ | ||||||
|  | // Copyright (C) 2003 Dolphin Project.
 | ||||||
|  | 
 | ||||||
|  | // This program is free software: you can redistribute it and/or modify
 | ||||||
|  | // it under the terms of the GNU General Public License as published by
 | ||||||
|  | // the Free Software Foundation, version 2.0.
 | ||||||
|  | 
 | ||||||
|  | // This program is distributed in the hope that it will be useful,
 | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | ||||||
|  | // GNU General Public License 2.0 for more details.
 | ||||||
|  | 
 | ||||||
|  | // A copy of the GPL 2.0 should have been included with the program.
 | ||||||
|  | // If not, see http://www.gnu.org/licenses/
 | ||||||
|  | 
 | ||||||
|  | // Official SVN repository and contact information can be found at
 | ||||||
|  | // http://code.google.com/p/dolphin-emu/
 | ||||||
|  | 
 | ||||||
|  | // WARNING - THIS LIBRARY IS NOT THREAD SAFE!!!
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <vector> | ||||||
|  | #include <stdint.h> | ||||||
|  | 
 | ||||||
|  | #include "assert.h" | ||||||
|  | #include "common_types.h" | ||||||
|  | 
 | ||||||
|  | // TODO: Check if Pandora still needs signal.h/kill here. Symbian doesn't.
 | ||||||
|  | 
 | ||||||
|  | // VCVT flags
 | ||||||
|  | #define TO_FLOAT      0 | ||||||
|  | #define TO_INT        1 << 0 | ||||||
|  | #define IS_SIGNED     1 << 1 | ||||||
|  | #define ROUND_TO_ZERO 1 << 2 | ||||||
|  | 
 | ||||||
|  | namespace FakeGen | ||||||
|  | { | ||||||
|  | enum FakeReg | ||||||
|  | { | ||||||
|  |     // GPRs
 | ||||||
|  |     R0 = 0, R1, R2, R3, R4, R5, | ||||||
|  |     R6, R7, R8, R9, R10, R11, | ||||||
|  | 
 | ||||||
|  |     // SPRs
 | ||||||
|  |     // R13 - R15 are SP, LR, and PC.
 | ||||||
|  |     // Almost always referred to by name instead of register number
 | ||||||
|  |     R12 = 12, R13 = 13, R14 = 14, R15 = 15, | ||||||
|  |     R_IP = 12, R_SP = 13, R_LR = 14, R_PC = 15, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     // VFP single precision registers
 | ||||||
|  |     S0, S1, S2, S3, S4, S5, S6, | ||||||
|  |     S7, S8, S9, S10, S11, S12, S13, | ||||||
|  |     S14, S15, S16, S17, S18, S19, S20, | ||||||
|  |     S21, S22, S23, S24, S25, S26, S27, | ||||||
|  |     S28, S29, S30, S31, | ||||||
|  | 
 | ||||||
|  |     // VFP Double Precision registers
 | ||||||
|  |     D0, D1, D2, D3, D4, D5, D6, D7, | ||||||
|  |     D8, D9, D10, D11, D12, D13, D14, D15, | ||||||
|  |     D16, D17, D18, D19, D20, D21, D22, D23, | ||||||
|  |     D24, D25, D26, D27, D28, D29, D30, D31, | ||||||
|  | 
 | ||||||
|  |     // ASIMD Quad-Word registers
 | ||||||
|  |     Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, | ||||||
|  |     Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15, | ||||||
|  | 
 | ||||||
|  |     // for NEON VLD/VST instructions
 | ||||||
|  |     REG_UPDATE = R13, | ||||||
|  |     INVALID_REG = 0xFFFFFFFF | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | enum CCFlags | ||||||
|  | { | ||||||
|  |     CC_EQ = 0, // Equal
 | ||||||
|  |     CC_NEQ, // Not equal
 | ||||||
|  |     CC_CS, // Carry Set
 | ||||||
|  |     CC_CC, // Carry Clear
 | ||||||
|  |     CC_MI, // Minus (Negative)
 | ||||||
|  |     CC_PL, // Plus
 | ||||||
|  |     CC_VS, // Overflow
 | ||||||
|  |     CC_VC, // No Overflow
 | ||||||
|  |     CC_HI, // Unsigned higher
 | ||||||
|  |     CC_LS, // Unsigned lower or same
 | ||||||
|  |     CC_GE, // Signed greater than or equal
 | ||||||
|  |     CC_LT, // Signed less than
 | ||||||
|  |     CC_GT, // Signed greater than
 | ||||||
|  |     CC_LE, // Signed less than or equal
 | ||||||
|  |     CC_AL, // Always (unconditional) 14
 | ||||||
|  |     CC_HS = CC_CS, // Alias of CC_CS  Unsigned higher or same
 | ||||||
|  |     CC_LO = CC_CC, // Alias of CC_CC  Unsigned lower
 | ||||||
|  | }; | ||||||
|  | const u32 NO_COND = 0xE0000000; | ||||||
|  | 
 | ||||||
|  | enum ShiftType | ||||||
|  | { | ||||||
|  |     ST_LSL = 0, | ||||||
|  |     ST_ASL = 0, | ||||||
|  |     ST_LSR = 1, | ||||||
|  |     ST_ASR = 2, | ||||||
|  |     ST_ROR = 3, | ||||||
|  |     ST_RRX = 4 | ||||||
|  | }; | ||||||
|  | enum IntegerSize | ||||||
|  | { | ||||||
|  |     I_I8 = 0, | ||||||
|  |     I_I16, | ||||||
|  |     I_I32, | ||||||
|  |     I_I64 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | enum | ||||||
|  | { | ||||||
|  |     NUMGPRs = 13, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | class FakeXEmitter; | ||||||
|  | 
 | ||||||
|  | enum OpType | ||||||
|  | { | ||||||
|  |     TYPE_IMM = 0, | ||||||
|  |     TYPE_REG, | ||||||
|  |     TYPE_IMMSREG, | ||||||
|  |     TYPE_RSR, | ||||||
|  |     TYPE_MEM | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // This is no longer a proper operand2 class. Need to split up.
 | ||||||
|  | class Operand2 | ||||||
|  | { | ||||||
|  |     friend class FakeXEmitter; | ||||||
|  | protected: | ||||||
|  |     u32 Value; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     OpType Type; | ||||||
|  | 
 | ||||||
|  |     // IMM types
 | ||||||
|  |     u8    Rotation; // Only for u8 values
 | ||||||
|  | 
 | ||||||
|  |     // Register types
 | ||||||
|  |     u8 IndexOrShift; | ||||||
|  |     ShiftType Shift; | ||||||
|  | public: | ||||||
|  |     OpType GetType() | ||||||
|  |     { | ||||||
|  |         return Type; | ||||||
|  |     } | ||||||
|  |     Operand2() {} | ||||||
|  |     Operand2(u32 imm, OpType type = TYPE_IMM) | ||||||
|  |     { | ||||||
|  |         Type = type; | ||||||
|  |         Value = imm; | ||||||
|  |         Rotation = 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Operand2(FakeReg Reg) | ||||||
|  |     { | ||||||
|  |         Type = TYPE_REG; | ||||||
|  |         Value = Reg; | ||||||
|  |         Rotation = 0; | ||||||
|  |     } | ||||||
|  |     Operand2(u8 imm, u8 rotation) | ||||||
|  |     { | ||||||
|  |         Type = TYPE_IMM; | ||||||
|  |         Value = imm; | ||||||
|  |         Rotation = rotation; | ||||||
|  |     } | ||||||
|  |     Operand2(FakeReg base, ShiftType type, FakeReg shift) // RSR
 | ||||||
|  |     { | ||||||
|  |         Type = TYPE_RSR; | ||||||
|  |         ASSERT_MSG(type != ST_RRX, "Invalid Operand2: RRX does not take a register shift amount"); | ||||||
|  |         IndexOrShift = shift; | ||||||
|  |         Shift = type; | ||||||
|  |         Value = base; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Operand2(FakeReg base, ShiftType type, u8 shift)// For IMM shifted register
 | ||||||
|  |     { | ||||||
|  |         if(shift == 32) shift = 0; | ||||||
|  |         switch (type) | ||||||
|  |         { | ||||||
|  |         case ST_LSL: | ||||||
|  |             ASSERT_MSG(shift < 32, "Invalid Operand2: LSL %u", shift); | ||||||
|  |             break; | ||||||
|  |         case ST_LSR: | ||||||
|  |             ASSERT_MSG(shift <= 32, "Invalid Operand2: LSR %u", shift); | ||||||
|  |             if (!shift) | ||||||
|  |                 type = ST_LSL; | ||||||
|  |             if (shift == 32) | ||||||
|  |                 shift = 0; | ||||||
|  |             break; | ||||||
|  |         case ST_ASR: | ||||||
|  |             ASSERT_MSG(shift < 32, "Invalid Operand2: ASR %u", shift); | ||||||
|  |             if (!shift) | ||||||
|  |                 type = ST_LSL; | ||||||
|  |             if (shift == 32) | ||||||
|  |                 shift = 0; | ||||||
|  |             break; | ||||||
|  |         case ST_ROR: | ||||||
|  |             ASSERT_MSG(shift < 32, "Invalid Operand2: ROR %u", shift); | ||||||
|  |             if (!shift) | ||||||
|  |                 type = ST_LSL; | ||||||
|  |             break; | ||||||
|  |         case ST_RRX: | ||||||
|  |             ASSERT_MSG(shift == 0, "Invalid Operand2: RRX does not take an immediate shift amount"); | ||||||
|  |             type = ST_ROR; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         IndexOrShift = shift; | ||||||
|  |         Shift = type; | ||||||
|  |         Value = base; | ||||||
|  |         Type = TYPE_IMMSREG; | ||||||
|  |     } | ||||||
|  |     u32 GetData() | ||||||
|  |     { | ||||||
|  |         switch(Type) | ||||||
|  |         { | ||||||
|  |         case TYPE_IMM: | ||||||
|  |             return Imm12Mod(); // This'll need to be changed later
 | ||||||
|  |         case TYPE_REG: | ||||||
|  |             return Rm(); | ||||||
|  |         case TYPE_IMMSREG: | ||||||
|  |             return IMMSR(); | ||||||
|  |         case TYPE_RSR: | ||||||
|  |             return RSR(); | ||||||
|  |         default: | ||||||
|  |             ASSERT_MSG(false, "GetData with Invalid Type"); | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     u32 IMMSR() // IMM shifted register
 | ||||||
|  |     { | ||||||
|  |         ASSERT_MSG(Type == TYPE_IMMSREG, "IMMSR must be imm shifted register"); | ||||||
|  |         return ((IndexOrShift & 0x1f) << 7 | (Shift << 5) | Value); | ||||||
|  |     } | ||||||
|  |     u32 RSR() // Register shifted register
 | ||||||
|  |     { | ||||||
|  |         ASSERT_MSG(Type == TYPE_RSR, "RSR must be RSR Of Course"); | ||||||
|  |         return (IndexOrShift << 8) | (Shift << 5) | 0x10 | Value; | ||||||
|  |     } | ||||||
|  |     u32 Rm() | ||||||
|  |     { | ||||||
|  |         ASSERT_MSG(Type == TYPE_REG, "Rm must be with Reg"); | ||||||
|  |         return Value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     u32 Imm5() | ||||||
|  |     { | ||||||
|  |         ASSERT_MSG((Type == TYPE_IMM), "Imm5 not IMM value"); | ||||||
|  |         return ((Value & 0x0000001F) << 7); | ||||||
|  |     } | ||||||
|  |     u32 Imm8() | ||||||
|  |     { | ||||||
|  |         ASSERT_MSG((Type == TYPE_IMM), "Imm8Rot not IMM value"); | ||||||
|  |         return Value & 0xFF; | ||||||
|  |     } | ||||||
|  |     u32 Imm8Rot() // IMM8 with Rotation
 | ||||||
|  |     { | ||||||
|  |         ASSERT_MSG((Type == TYPE_IMM), "Imm8Rot not IMM value"); | ||||||
|  |         ASSERT_MSG((Rotation & 0xE1) != 0, "Invalid Operand2: immediate rotation %u", Rotation); | ||||||
|  |         return (1 << 25) | (Rotation << 7) | (Value & 0x000000FF); | ||||||
|  |     } | ||||||
|  |     u32 Imm12() | ||||||
|  |     { | ||||||
|  |         ASSERT_MSG((Type == TYPE_IMM), "Imm12 not IMM"); | ||||||
|  |         return (Value & 0x00000FFF); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     u32 Imm12Mod() | ||||||
|  |     { | ||||||
|  |         // This is an IMM12 with the top four bits being rotation and the
 | ||||||
|  |         // bottom eight being an IMM. This is for instructions that need to
 | ||||||
|  |         // expand a 8bit IMM to a 32bit value and gives you some rotation as
 | ||||||
|  |         // well.
 | ||||||
|  |         // Each rotation rotates to the right by 2 bits
 | ||||||
|  |         ASSERT_MSG((Type == TYPE_IMM), "Imm12Mod not IMM"); | ||||||
|  |         return ((Rotation & 0xF) << 8) | (Value & 0xFF); | ||||||
|  |     } | ||||||
|  |     u32 Imm16() | ||||||
|  |     { | ||||||
|  |         ASSERT_MSG((Type == TYPE_IMM), "Imm16 not IMM"); | ||||||
|  |         return ( (Value & 0xF000) << 4) | (Value & 0x0FFF); | ||||||
|  |     } | ||||||
|  |     u32 Imm16Low() | ||||||
|  |     { | ||||||
|  |         return Imm16(); | ||||||
|  |     } | ||||||
|  |     u32 Imm16High() // Returns high 16bits
 | ||||||
|  |     { | ||||||
|  |         ASSERT_MSG((Type == TYPE_IMM), "Imm16 not IMM"); | ||||||
|  |         return ( ((Value >> 16) & 0xF000) << 4) | ((Value >> 16) & 0x0FFF); | ||||||
|  |     } | ||||||
|  |     u32 Imm24() | ||||||
|  |     { | ||||||
|  |         ASSERT_MSG((Type == TYPE_IMM), "Imm16 not IMM"); | ||||||
|  |         return (Value & 0x0FFFFFFF); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Use these when you don't know if an imm can be represented as an operand2.
 | ||||||
|  | // This lets you generate both an optimal and a fallback solution by checking
 | ||||||
|  | // the return value, which will be false if these fail to find a Operand2 that
 | ||||||
|  | // represents your 32-bit imm value.
 | ||||||
|  | bool TryMakeOperand2(u32 imm, Operand2 &op2); | ||||||
|  | bool TryMakeOperand2_AllowInverse(u32 imm, Operand2 &op2, bool *inverse); | ||||||
|  | bool TryMakeOperand2_AllowNegation(s32 imm, Operand2 &op2, bool *negated); | ||||||
|  | 
 | ||||||
|  | // Use this only when you know imm can be made into an Operand2.
 | ||||||
|  | Operand2 AssumeMakeOperand2(u32 imm); | ||||||
|  | 
 | ||||||
|  | inline Operand2 R(FakeReg Reg)    { return Operand2(Reg, TYPE_REG); } | ||||||
|  | inline Operand2 IMM(u32 Imm)    { return Operand2(Imm, TYPE_IMM); } | ||||||
|  | inline Operand2 Mem(void *ptr)    { return Operand2((u32)(uintptr_t)ptr, TYPE_IMM); } | ||||||
|  | //usage: struct {int e;} s; STRUCT_OFFSET(s,e)
 | ||||||
|  | #define STRUCT_OFF(str,elem) ((u32)((u32)&(str).elem-(u32)&(str))) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | struct FixupBranch | ||||||
|  | { | ||||||
|  |     u8 *ptr; | ||||||
|  |     u32 condition; // Remembers our codition at the time
 | ||||||
|  |     int type; //0 = B 1 = BL
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef const u8* JumpTarget; | ||||||
|  | 
 | ||||||
|  | // XXX: Stop polluting the global namespace
 | ||||||
|  | const u32 I_8 = (1 << 0); | ||||||
|  | const u32 I_16 = (1 << 1); | ||||||
|  | const u32 I_32 = (1 << 2); | ||||||
|  | const u32 I_64 = (1 << 3); | ||||||
|  | const u32 I_SIGNED = (1 << 4); | ||||||
|  | const u32 I_UNSIGNED = (1 << 5); | ||||||
|  | const u32 F_32 = (1 << 6); | ||||||
|  | const u32 I_POLYNOMIAL = (1 << 7); // Only used in VMUL/VMULL
 | ||||||
|  | 
 | ||||||
|  | u32 EncodeVd(FakeReg Vd); | ||||||
|  | u32 EncodeVn(FakeReg Vn); | ||||||
|  | u32 EncodeVm(FakeReg Vm); | ||||||
|  | 
 | ||||||
|  | u32 encodedSize(u32 value); | ||||||
|  | 
 | ||||||
|  | // Subtracts the base from the register to give us the real one
 | ||||||
|  | FakeReg SubBase(FakeReg Reg); | ||||||
|  | 
 | ||||||
|  | // See A.7.1 in the Fakev7-A
 | ||||||
|  | // VMUL F32 scalars can only be up to D15[0], D15[1] - higher scalars cannot be individually addressed
 | ||||||
|  | FakeReg DScalar(FakeReg dreg, int subScalar); | ||||||
|  | FakeReg QScalar(FakeReg qreg, int subScalar); | ||||||
|  | 
 | ||||||
|  | enum NEONAlignment { | ||||||
|  |     ALIGN_NONE = 0, | ||||||
|  |     ALIGN_64 = 1, | ||||||
|  |     ALIGN_128 = 2, | ||||||
|  |     ALIGN_256 = 3 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class NEONXEmitter; | ||||||
|  | 
 | ||||||
|  | class FakeXEmitter | ||||||
|  | { | ||||||
|  |     friend struct OpArg;  // for Write8 etc
 | ||||||
|  | private: | ||||||
|  |     u8 *code, *startcode; | ||||||
|  |     u8 *lastCacheFlushEnd; | ||||||
|  |     u32 condition; | ||||||
|  | 
 | ||||||
|  | protected: | ||||||
|  |     inline void Write32(u32 value) {*(u32*)code = value; code+=4;} | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  |     FakeXEmitter() : code(0), startcode(0), lastCacheFlushEnd(0) { | ||||||
|  |         condition = CC_AL << 28; | ||||||
|  |     } | ||||||
|  |     FakeXEmitter(u8 *code_ptr) { | ||||||
|  |         code = code_ptr; | ||||||
|  |         lastCacheFlushEnd = code_ptr; | ||||||
|  |         startcode = code_ptr; | ||||||
|  |         condition = CC_AL << 28; | ||||||
|  |     } | ||||||
|  |     virtual ~FakeXEmitter() {} | ||||||
|  | 
 | ||||||
|  |     void SetCodePtr(u8 *ptr) {} | ||||||
|  |     void ReserveCodeSpace(u32 bytes) {} | ||||||
|  |     const u8 *AlignCode16() { return nullptr; } | ||||||
|  |     const u8 *AlignCodePage() { return nullptr; } | ||||||
|  |     const u8 *GetCodePtr() const { return nullptr; } | ||||||
|  |     void FlushIcache() {} | ||||||
|  |     void FlushIcacheSection(u8 *start, u8 *end) {} | ||||||
|  |     u8 *GetWritableCodePtr() { return nullptr; } | ||||||
|  | 
 | ||||||
|  |     CCFlags GetCC() { return CCFlags(condition >> 28); } | ||||||
|  |     void SetCC(CCFlags cond = CC_AL) {} | ||||||
|  | 
 | ||||||
|  |     // Special purpose instructions
 | ||||||
|  | 
 | ||||||
|  |     // Do nothing
 | ||||||
|  |     void NOP(int count = 1) {} //nop padding - TODO: fast nop slides, for amd and intel (check their manuals)
 | ||||||
|  | 
 | ||||||
|  | #ifdef CALL | ||||||
|  | #undef CALL | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |     void QuickCallFunction(FakeReg scratchreg, const void *func); | ||||||
|  |     template <typename T> void QuickCallFunction(FakeReg scratchreg, T func) { | ||||||
|  |         QuickCallFunction(scratchreg, (const void *)func); | ||||||
|  |     } | ||||||
|  | };  // class FakeXEmitter
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Everything that needs to generate machine code should inherit from this.
 | ||||||
|  | // You get memory management for free, plus, you can use all the MOV etc functions without
 | ||||||
|  | // having to prefix them with gen-> or something similar.
 | ||||||
|  | class FakeXCodeBlock : public FakeXEmitter | ||||||
|  | { | ||||||
|  | protected: | ||||||
|  |     u8 *region; | ||||||
|  |     size_t region_size; | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  |     FakeXCodeBlock() : region(NULL), region_size(0) {} | ||||||
|  |     virtual ~FakeXCodeBlock() { if (region) FreeCodeSpace(); } | ||||||
|  | 
 | ||||||
|  |     // Call this before you generate any code.
 | ||||||
|  |     void AllocCodeSpace(int size) { } | ||||||
|  | 
 | ||||||
|  |     // Always clear code space with breakpoints, so that if someone accidentally executes
 | ||||||
|  |     // uninitialized, it just breaks into the debugger.
 | ||||||
|  |     void ClearCodeSpace() { } | ||||||
|  | 
 | ||||||
|  |     // Call this when shutting down. Don't rely on the destructor, even though it'll do the job.
 | ||||||
|  |     void FreeCodeSpace() { } | ||||||
|  | 
 | ||||||
|  |     bool IsInSpace(const u8 *ptr) const | ||||||
|  |     { | ||||||
|  |         return ptr >= region && ptr < region + region_size; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Cannot currently be undone. Will write protect the entire code region.
 | ||||||
|  |     // Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()).
 | ||||||
|  |     void WriteProtect() { } | ||||||
|  |     void UnWriteProtect() { } | ||||||
|  | 
 | ||||||
|  |     void ResetCodePtr() | ||||||
|  |     { | ||||||
|  |         SetCodePtr(region); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     size_t GetSpaceLeft() const | ||||||
|  |     { | ||||||
|  |         return region_size - (GetCodePtr() - region); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     u8 *GetBasePtr() { | ||||||
|  |         return region; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     size_t GetOffset(const u8 *ptr) const { | ||||||
|  |         return ptr - region; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | }  // namespace
 | ||||||
|  | @ -27,7 +27,7 @@ | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
| // Platform detection
 | // Platform detection
 | ||||||
| 
 | 
 | ||||||
| #if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) | #if defined(__x86_64__) || defined(_M_X86_64) || defined(__aarch64__) | ||||||
|     #define EMU_ARCH_BITS 64 |     #define EMU_ARCH_BITS 64 | ||||||
| #elif defined(__i386) || defined(_M_IX86) || defined(__arm__) || defined(_M_ARM) | #elif defined(__i386) || defined(_M_IX86) || defined(__arm__) || defined(_M_ARM) | ||||||
|     #define EMU_ARCH_BITS 32 |     #define EMU_ARCH_BITS 32 | ||||||
|  |  | ||||||
							
								
								
									
										1989
									
								
								src/common/x64_emitter.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1989
									
								
								src/common/x64_emitter.cpp
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										1067
									
								
								src/common/x64_emitter.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1067
									
								
								src/common/x64_emitter.h
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bunnei
						bunnei