diff --git a/CMakeLists.txt b/CMakeLists.txt index 54b7160cf9..baad81aca4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -405,6 +405,16 @@ if(NOT ANDROID) message("OpenAL NOT found, disabling OpenAL sound backend") endif(OPENAL_FOUND) + include(FindLLVM OPTIONAL) + if (LLVM_FOUND) + add_definitions(-DHAS_LLVM=1) + set(HAS_LLVM 1) + + include_directories(${LLVM_INCLUDE_DIRS}) + + message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") + endif() + set(USE_X11 0) if(UNIX AND NOT APPLE) diff --git a/CMakeTests/FindLLVM.cmake b/CMakeTests/FindLLVM.cmake new file mode 100644 index 0000000000..ab7c50cbe6 --- /dev/null +++ b/CMakeTests/FindLLVM.cmake @@ -0,0 +1,22 @@ +# This file only exists because LLVM's cmake files are broken. +# This affects both LLVM 3.4 and 3.5. +# Hopefully when they fix their cmake system we don't need this garbage. +list(APPEND LLVM_CONFIG_EXECUTABLES "llvm-config") +list(APPEND LLVM_CONFIG_EXECUTABLES "llvm-config-3.5") +list(APPEND LLVM_CONFIG_EXECUTABLES "llvm-config-3.4") + +foreach(LLVM_CONFIG_NAME ${LLVM_CONFIG_EXECUTABLES}) + find_program(LLVM_CONFIG_EXE NAMES ${LLVM_CONFIG_NAME}) + if (LLVM_CONFIG_EXE) + set(LLVM_FOUND 1) + execute_process(COMMAND ${LLVM_CONFIG_EXE} --includedir --prefix OUTPUT_VARIABLE LLVM_INCLUDE_DIRS + OUTPUT_STRIP_TRAILING_WHITESPACE ) + execute_process(COMMAND ${LLVM_CONFIG_EXE} --ldflags --prefix OUTPUT_VARIABLE LLVM_DEFINITIONS + OUTPUT_STRIP_TRAILING_WHITESPACE ) + execute_process(COMMAND ${LLVM_CONFIG_EXE} --libs Core --prefix OUTPUT_VARIABLE LLVM_LIBRARIES + OUTPUT_STRIP_TRAILING_WHITESPACE ) + execute_process(COMMAND ${LLVM_CONFIG_EXE} --version --prefix OUTPUT_VARIABLE LLVM_PACKAGE_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE ) + break() + endif() +endforeach() diff --git a/Source/Core/DolphinWX/CMakeLists.txt b/Source/Core/DolphinWX/CMakeLists.txt index 2a90556049..cdcb08685e 100644 --- a/Source/Core/DolphinWX/CMakeLists.txt +++ b/Source/Core/DolphinWX/CMakeLists.txt @@ -178,7 +178,7 @@ if(ANDROID) set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} ${DOLPHIN_EXE}) elseif(wxWidgets_FOUND) add_executable(${DOLPHIN_EXE} ${SRCS} ${GUI_SRCS}) - target_link_libraries(${DOLPHIN_EXE} ${LIBS} ${WXLIBS}) + target_link_libraries(${DOLPHIN_EXE} ${LIBS} ${WXLIBS} ${LLVM_LIBRARIES}) if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") include(BundleUtilities) set(BUNDLE_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${DOLPHIN_EXE}.app) diff --git a/Source/Core/DolphinWX/Debugger/JitWindow.cpp b/Source/Core/DolphinWX/Debugger/JitWindow.cpp index e17546181d..052f38cf04 100644 --- a/Source/Core/DolphinWX/Debugger/JitWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/JitWindow.cpp @@ -7,6 +7,14 @@ #include // Bochs #include +#if defined(HAS_LLVM) +// PowerPC.h defines PC. +// This conflicts with a function that has an argument named PC +#undef PC +#include +#include +#endif + #include #include #include @@ -33,6 +41,68 @@ #include "DolphinWX/WxUtils.h" #include "DolphinWX/Debugger/JitWindow.h" +#if defined(HAS_LLVM) +// This class declaration should be in the header +// Due to the conflict with the PC define and the function with PC as an argument +// it has to be in this file instead. +// Once that conflict is resolved this can be moved to the header +class HostDisassemblerLLVM : public HostDisassembler +{ +public: + HostDisassemblerLLVM(const std::string host_disasm); + ~HostDisassemblerLLVM() + { + if (m_can_disasm) + LLVMDisasmDispose(m_llvm_context); + } + +private: + bool m_can_disasm; + LLVMDisasmContextRef m_llvm_context; + + std::string DisassembleHostBlock(const u8* code_start, const u32 code_size, u32* host_instructions_count) override; +}; + +HostDisassemblerLLVM::HostDisassemblerLLVM(const std::string host_disasm) + : m_can_disasm(false) +{ + LLVMInitializeAllTargetInfos(); + LLVMInitializeAllTargetMCs(); + LLVMInitializeAllDisassemblers(); + + m_llvm_context = LLVMCreateDisasm(host_disasm.c_str(), nullptr, 0, 0, nullptr); + + // Couldn't create llvm context + if (!m_llvm_context) + return; + LLVMSetDisasmOptions(m_llvm_context, + LLVMDisassembler_Option_AsmPrinterVariant | + LLVMDisassembler_Option_PrintLatency); + + m_can_disasm = true; +} + +std::string HostDisassemblerLLVM::DisassembleHostBlock(const u8* code_start, const u32 code_size, u32 *host_instructions_count) +{ + if (!m_can_disasm) + return "(No LLVM context)"; + + u64 disasmPtr = (u64)code_start; + const u8 *end = code_start + code_size; + + std::ostringstream x86_disasm; + while ((u8*)disasmPtr < end) + { + char inst_disasm[256]; + disasmPtr += LLVMDisasmInstruction(m_llvm_context, (u8*)disasmPtr, (u64)(end - disasmPtr), (u64)disasmPtr, inst_disasm, 256); + x86_disasm << inst_disasm << std::endl; + (*host_instructions_count)++; + } + + return x86_disasm.str(); +} +#endif + std::string HostDisassembler::DisassembleBlock(u32* address, u32* host_instructions_count, u32* code_size) { if (!jit) @@ -143,8 +213,14 @@ CJitWindow::CJitWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos, sizerSplit->Fit(this); sizerBig->Fit(this); -#ifdef _M_X86 +#if defined(_M_X86) && defined(HAS_LLVM) + m_disassembler.reset(new HostDisassemblerLLVM("x86_64-none-unknown")); +#elif defined(_M_X86) m_disassembler.reset(new HostDisassemblerX86()); +#elif defined(_M_ARM_64) && defined(HAS_LLVM) + m_disassembler.reset(new HostDisassemblerLLVM("aarch64-none-unknown")); +#elif defined(_M_ARM_32) && defined(HAS_LLVM) + m_disassembler.reset(new HostDisassemblerLLVM("armv7-none-unknown")); #else m_disassembler.reset(new HostDisassembler()); #endif diff --git a/Source/Core/DolphinWX/Debugger/JitWindow.h b/Source/Core/DolphinWX/Debugger/JitWindow.h index 02f4d01cdc..d7d36de7cd 100644 --- a/Source/Core/DolphinWX/Debugger/JitWindow.h +++ b/Source/Core/DolphinWX/Debugger/JitWindow.h @@ -39,7 +39,7 @@ public: std::string DisassembleBlock(u32* address, u32* host_instructions_count, u32* code_size); private: - virtual std::string DisassembleHostBlock(const u8* code_start, const u32 code_size, u32* host_instructions_count) { return ""; } + virtual std::string DisassembleHostBlock(const u8* code_start, const u32 code_size, u32* host_instructions_count) { return "(No disassembler)"; } }; class HostDisassemblerX86 : public HostDisassembler