PPU/LLVM: Fix build

This commit is contained in:
vlj 2015-07-21 17:11:01 +02:00 committed by Nekotekina
parent b3dfa4f5a2
commit 7592b87a90
3 changed files with 92 additions and 68 deletions

View file

@ -7,6 +7,8 @@
#include "llvm/Support/Host.h" #include "llvm/Support/Host.h"
#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/ManagedStatic.h"
#include "llvm/ExecutionEngine/GenericValue.h" #include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/IR/Intrinsics.h" #include "llvm/IR/Intrinsics.h"
#include "llvm/Support/FileSystem.h" #include "llvm/Support/FileSystem.h"
#include "llvm/Analysis/Passes.h" #include "llvm/Analysis/Passes.h"
@ -40,49 +42,14 @@ Compiler::Compiler(RecompilationEngine & recompilation_engine, const Executable
m_llvm_context = new LLVMContext(); m_llvm_context = new LLVMContext();
m_ir_builder = new IRBuilder<>(*m_llvm_context); m_ir_builder = new IRBuilder<>(*m_llvm_context);
m_module = new llvm::Module("Module", *m_llvm_context);
m_fpm = new FunctionPassManager(m_module);
EngineBuilder engine_builder(m_module);
engine_builder.setMCPU(sys::getHostCPUName());
engine_builder.setEngineKind(EngineKind::JIT);
engine_builder.setOptLevel(CodeGenOpt::Default);
m_execution_engine = engine_builder.create();
m_fpm->add(new DataLayoutPass(m_module));
m_fpm->add(createNoAAPass());
m_fpm->add(createBasicAliasAnalysisPass());
m_fpm->add(createNoTargetTransformInfoPass());
m_fpm->add(createEarlyCSEPass());
m_fpm->add(createTailCallEliminationPass());
m_fpm->add(createReassociatePass());
m_fpm->add(createInstructionCombiningPass());
m_fpm->add(new DominatorTreeWrapperPass());
m_fpm->add(new MemoryDependenceAnalysis());
m_fpm->add(createGVNPass());
m_fpm->add(createInstructionCombiningPass());
m_fpm->add(new MemoryDependenceAnalysis());
m_fpm->add(createDeadStoreEliminationPass());
m_fpm->add(new LoopInfo());
m_fpm->add(new ScalarEvolution());
m_fpm->add(createSLPVectorizerPass());
m_fpm->add(createInstructionCombiningPass());
m_fpm->add(createCFGSimplificationPass());
m_fpm->doInitialization();
std::vector<Type *> arg_types; std::vector<Type *> arg_types;
arg_types.push_back(m_ir_builder->getInt8PtrTy()); arg_types.push_back(m_ir_builder->getInt8PtrTy());
arg_types.push_back(m_ir_builder->getInt8PtrTy());
arg_types.push_back(m_ir_builder->getInt64Ty()); arg_types.push_back(m_ir_builder->getInt64Ty());
m_compiled_function_type = FunctionType::get(m_ir_builder->getInt32Ty(), arg_types, false); m_compiled_function_type = FunctionType::get(m_ir_builder->getInt32Ty(), arg_types, false);
m_execute_unknown_function = (Function *)m_module->getOrInsertFunction("execute_unknown_function", m_compiled_function_type); m_executableMap["execute_unknown_function"] = execute_unknown_function;
m_execute_unknown_function->setCallingConv(CallingConv::X86_64_Win64); m_executableMap["execute_unknown_block"] = execute_unknown_block;
m_execution_engine->addGlobalMapping(m_execute_unknown_function, (void *)execute_unknown_function);
m_execute_unknown_block = (Function *)m_module->getOrInsertFunction("execute_unknown_block", m_compiled_function_type);
m_execute_unknown_block->setCallingConv(CallingConv::X86_64_Win64);
m_execution_engine->addGlobalMapping(m_execute_unknown_block, (void *)execute_unknown_block);
if (!s_rotate_mask_inited) { if (!s_rotate_mask_inited) {
InitRotateMask(); InitRotateMask();
@ -91,15 +58,75 @@ Compiler::Compiler(RecompilationEngine & recompilation_engine, const Executable
} }
Compiler::~Compiler() { Compiler::~Compiler() {
delete m_execution_engine; for (auto execution_engine : m_execution_engines)
delete m_fpm; delete execution_engine;
delete m_ir_builder; delete m_ir_builder;
delete m_llvm_context; delete m_llvm_context;
} }
class CustomSectionMemoryManager : public llvm::SectionMemoryManager {
private:
std::unordered_map<std::string, Executable> &executableMap;
public:
CustomSectionMemoryManager(std::unordered_map<std::string, Executable> &map) :
executableMap(map)
{}
~CustomSectionMemoryManager() override {}
virtual uint64_t getSymbolAddress(const std::string &Name)
{
std::unordered_map<std::string, Executable>::const_iterator It = executableMap.find(Name);
if (It != executableMap.end())
return (uint64_t)It->second;
return 0;
}
};
Executable Compiler::Compile(const std::string & name, const ControlFlowGraph & cfg, bool inline_all, bool generate_linkable_exits) { Executable Compiler::Compile(const std::string & name, const ControlFlowGraph & cfg, bool inline_all, bool generate_linkable_exits) {
auto compilation_start = std::chrono::high_resolution_clock::now(); auto compilation_start = std::chrono::high_resolution_clock::now();
m_module = new llvm::Module("Module", *m_llvm_context);
m_execute_unknown_function = (Function *)m_module->getOrInsertFunction("execute_unknown_function", m_compiled_function_type);
m_execute_unknown_function->setCallingConv(CallingConv::X86_64_Win64);
m_execute_unknown_block = (Function *)m_module->getOrInsertFunction("execute_unknown_block", m_compiled_function_type);
m_execute_unknown_block->setCallingConv(CallingConv::X86_64_Win64);
std::string targetTriple = "x86_64-pc-windows-elf";
m_module->setTargetTriple(targetTriple);
llvm::ExecutionEngine *execution_engine =
EngineBuilder(std::unique_ptr<llvm::Module>(m_module))
.setEngineKind(EngineKind::JIT)
.setMCJITMemoryManager(std::unique_ptr<llvm::SectionMemoryManager>(new CustomSectionMemoryManager(m_executableMap)))
.setOptLevel(llvm::CodeGenOpt::Aggressive)
.setMCPU("nehalem")
.create();
m_module->setDataLayout(execution_engine->getDataLayout());
llvm::FunctionPassManager *fpm = new llvm::FunctionPassManager(m_module);
fpm->add(createNoAAPass());
fpm->add(createBasicAliasAnalysisPass());
fpm->add(createNoTargetTransformInfoPass());
fpm->add(createEarlyCSEPass());
fpm->add(createTailCallEliminationPass());
fpm->add(createReassociatePass());
fpm->add(createInstructionCombiningPass());
fpm->add(new DominatorTreeWrapperPass());
fpm->add(new MemoryDependenceAnalysis());
fpm->add(createGVNPass());
fpm->add(createInstructionCombiningPass());
fpm->add(new MemoryDependenceAnalysis());
fpm->add(createDeadStoreEliminationPass());
fpm->add(new LoopInfo());
fpm->add(new ScalarEvolution());
fpm->add(createSLPVectorizerPass());
fpm->add(createInstructionCombiningPass());
fpm->add(createCFGSimplificationPass());
fpm->doInitialization();
m_state.cfg = &cfg; m_state.cfg = &cfg;
m_state.inline_all = inline_all; m_state.inline_all = inline_all;
m_state.generate_linkable_exits = generate_linkable_exits; m_state.generate_linkable_exits = generate_linkable_exits;
@ -228,32 +255,32 @@ Executable Compiler::Compile(const std::string & name, const ControlFlowGraph &
} }
} }
#ifdef _DEBUG
m_recompilation_engine.Log() << *m_state.function; m_recompilation_engine.Log() << *m_module;
std::string verify; std::string verify;
raw_string_ostream verify_ostream(verify); raw_string_ostream verify_ostream(verify);
if (verifyFunction(*m_state.function, &verify_ostream)) { if (verifyFunction(*m_state.function, &verify_ostream)) {
m_recompilation_engine.Log() << "Verification failed: " << verify << "\n"; m_recompilation_engine.Log() << "Verification failed: " << verify << "\n";
} }
#endif
auto ir_build_end = std::chrono::high_resolution_clock::now(); auto ir_build_end = std::chrono::high_resolution_clock::now();
m_stats.ir_build_time += std::chrono::duration_cast<std::chrono::nanoseconds>(ir_build_end - compilation_start); m_stats.ir_build_time += std::chrono::duration_cast<std::chrono::nanoseconds>(ir_build_end - compilation_start);
// Optimize this function // Optimize this function
m_fpm->run(*m_state.function); fpm->run(*m_state.function);
auto optimize_end = std::chrono::high_resolution_clock::now(); auto optimize_end = std::chrono::high_resolution_clock::now();
m_stats.optimization_time += std::chrono::duration_cast<std::chrono::nanoseconds>(optimize_end - ir_build_end); m_stats.optimization_time += std::chrono::duration_cast<std::chrono::nanoseconds>(optimize_end - ir_build_end);
// Translate to machine code // Translate to machine code
MachineCodeInfo mci; execution_engine->finalizeObject();
m_execution_engine->runJITOnFunction(m_state.function, &mci); void *function = execution_engine->getPointerToFunction(m_state.function);
auto translate_end = std::chrono::high_resolution_clock::now(); auto translate_end = std::chrono::high_resolution_clock::now();
m_stats.translation_time += std::chrono::duration_cast<std::chrono::nanoseconds>(translate_end - optimize_end); m_stats.translation_time += std::chrono::duration_cast<std::chrono::nanoseconds>(translate_end - optimize_end);
m_execution_engines.push_back(execution_engine);
#ifdef _DEBUG /* m_recompilation_engine.Log() << "\nDisassembly:\n";
m_recompilation_engine.Log() << "\nDisassembly:\n";
auto disassembler = LLVMCreateDisasm(sys::getProcessTriple().c_str(), nullptr, 0, nullptr, nullptr); auto disassembler = LLVMCreateDisasm(sys::getProcessTriple().c_str(), nullptr, 0, nullptr, nullptr);
for (size_t pc = 0; pc < mci.size();) { for (size_t pc = 0; pc < mci.size();) {
char str[1024]; char str[1024];
@ -263,19 +290,20 @@ Executable Compiler::Compile(const std::string & name, const ControlFlowGraph &
pc += size; pc += size;
} }
LLVMDisasmDispose(disassembler); LLVMDisasmDispose(disassembler);*/
#endif
auto compilation_end = std::chrono::high_resolution_clock::now(); auto compilation_end = std::chrono::high_resolution_clock::now();
m_stats.total_time += std::chrono::duration_cast<std::chrono::nanoseconds>(compilation_end - compilation_start); m_stats.total_time += std::chrono::duration_cast<std::chrono::nanoseconds>(compilation_end - compilation_start);
delete fpm;
return (Executable)mci.address(); assert(function != nullptr);
return (Executable)function;
} }
void Compiler::FreeExecutable(const std::string & name) { void Compiler::FreeExecutable(const std::string & name) {
auto function = m_module->getFunction(name); auto function = m_module->getFunction(name);
if (function) { if (function) {
m_execution_engine->freeMachineCodeForFunction(function); // m_execution_engine->freeMachineCodeForFunction(function);
function->eraseFromParent(); function->eraseFromParent();
} }
} }
@ -4990,13 +5018,11 @@ BasicBlock * Compiler::GetBasicBlockFromAddress(u32 address, const std::string &
break; break;
} }
#ifdef _DEBUG
auto block_address = GetAddressFromBasicBlockName(i->getName()); auto block_address = GetAddressFromBasicBlockName(i->getName());
if (block_address > address) { if (block_address > address) {
next_block = &(*i); next_block = &(*i);
break; break;
} }
#endif
} }
if (!block && create_if_not_exist) { if (!block && create_if_not_exist) {
@ -5551,7 +5577,8 @@ Value * Compiler::Call(const char * name, Func function, Args... args) {
auto fn_type = FunctionType::get(CppToLlvmType<ReturnType>(), fn_args_type, false); auto fn_type = FunctionType::get(CppToLlvmType<ReturnType>(), fn_args_type, false);
fn = cast<Function>(m_module->getOrInsertFunction(name, fn_type)); fn = cast<Function>(m_module->getOrInsertFunction(name, fn_type));
fn->setCallingConv(CallingConv::X86_64_Win64); fn->setCallingConv(CallingConv::X86_64_Win64);
m_execution_engine->addGlobalMapping(fn, (void *&)function); // Note: not threadsafe
m_executableMap[name] = (Executable)(void *&)function;
} }
std::vector<Value *> fn_args = {args...}; std::vector<Value *> fn_args = {args...};
@ -5656,7 +5683,7 @@ void RecompilationEngine::NotifyTrace(ExecutionTrace * execution_trace) {
raw_fd_ostream & RecompilationEngine::Log() { raw_fd_ostream & RecompilationEngine::Log() {
if (!m_log) { if (!m_log) {
std::string error; std::error_code error;
m_log = new raw_fd_ostream("PPULLVMRecompiler.log", error, sys::fs::F_Text); m_log = new raw_fd_ostream("PPULLVMRecompiler.log", error, sys::fs::F_Text);
m_log->SetUnbuffered(); m_log->SetUnbuffered();
} }
@ -5756,9 +5783,7 @@ void RecompilationEngine::ProcessExecutionTrace(const ExecutionTrace & execution
auto execution_trace_id = execution_trace.GetId(); auto execution_trace_id = execution_trace.GetId();
auto processed_execution_trace_i = m_processed_execution_traces.find(execution_trace_id); auto processed_execution_trace_i = m_processed_execution_traces.find(execution_trace_id);
if (processed_execution_trace_i == m_processed_execution_traces.end()) { if (processed_execution_trace_i == m_processed_execution_traces.end()) {
#ifdef _DEBUG
Log() << "Trace: " << execution_trace.ToString() << "\n"; Log() << "Trace: " << execution_trace.ToString() << "\n";
#endif
// Find the function block // Find the function block
BlockEntry key(execution_trace.function_address, execution_trace.function_address); BlockEntry key(execution_trace.function_address, execution_trace.function_address);
auto block_i = m_block_table.find(&key); auto block_i = m_block_table.find(&key);
@ -5841,10 +5866,8 @@ void RecompilationEngine::UpdateControlFlowGraph(ControlFlowGraph & cfg, const E
} }
void RecompilationEngine::CompileBlock(BlockEntry & block_entry) { void RecompilationEngine::CompileBlock(BlockEntry & block_entry) {
#ifdef _DEBUG
Log() << "Compile: " << block_entry.ToString() << "\n"; Log() << "Compile: " << block_entry.ToString() << "\n";
Log() << "CFG: " << block_entry.cfg.ToString() << "\n"; Log() << "CFG: " << block_entry.cfg.ToString() << "\n";
#endif
auto ordinal = AllocateOrdinal(block_entry.cfg.start_address, block_entry.IsFunction()); auto ordinal = AllocateOrdinal(block_entry.cfg.start_address, block_entry.IsFunction());
auto executable = m_compiler.Compile(fmt::Format("fn_0x%08X_%u", block_entry.cfg.start_address, block_entry.revision++), block_entry.cfg, true, auto executable = m_compiler.Compile(fmt::Format("fn_0x%08X_%u", block_entry.cfg.start_address, block_entry.revision++), block_entry.cfg, true,

View file

@ -8,6 +8,7 @@
#include "Emu/Cell/PPUDecoder.h" #include "Emu/Cell/PPUDecoder.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/PPUInterpreter.h" #include "Emu/Cell/PPUInterpreter.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include "llvm/IR/LLVMContext.h" #include "llvm/IR/LLVMContext.h"
#include "llvm/IR/IRBuilder.h" #include "llvm/IR/IRBuilder.h"
@ -745,6 +746,9 @@ namespace ppu_recompiler_llvm {
/// The executable that will be called to execute unknown blocks /// The executable that will be called to execute unknown blocks
llvm::Function * m_execute_unknown_block; llvm::Function * m_execute_unknown_block;
/// Maps function name to executable memory pointer
std::unordered_map<std::string, Executable> m_executableMap;
/// LLVM context /// LLVM context
llvm::LLVMContext * m_llvm_context; llvm::LLVMContext * m_llvm_context;
@ -754,11 +758,8 @@ namespace ppu_recompiler_llvm {
/// Module to which all generated code is output to /// Module to which all generated code is output to
llvm::Module * m_module; llvm::Module * m_module;
/// JIT execution engine /// Execution engine list. An execution engine is a JITed function
llvm::ExecutionEngine * m_execution_engine; std::vector<llvm::ExecutionEngine *> m_execution_engines;
/// Function pass manager
llvm::FunctionPassManager * m_fpm;
/// LLVM type of the functions genreated by the compiler /// LLVM type of the functions genreated by the compiler
llvm::FunctionType * m_compiled_function_type; llvm::FunctionType * m_compiled_function_type;

View file

@ -656,7 +656,7 @@
<ExcludePath>$(ExcludePath)</ExcludePath> <ExcludePath>$(ExcludePath)</ExcludePath>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">
<IncludePath>.\;..\;..\minidx9\Include;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include</IncludePath> <IncludePath>.\;..\;..\minidx9\Include;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include;$(UniversalCRT_IncludePath)</IncludePath>
<IntDir>$(Platform)\$(Configuration)\emucore\</IntDir> <IntDir>$(Platform)\$(Configuration)\emucore\</IntDir>
<LibraryPath>$(LibraryPath)</LibraryPath> <LibraryPath>$(LibraryPath)</LibraryPath>
<ExcludePath>$(ExcludePath)</ExcludePath> <ExcludePath>$(ExcludePath)</ExcludePath>
@ -715,7 +715,7 @@
</Link> </Link>
<Lib> <Lib>
<AdditionalLibraryDirectories>..\llvm_build\Debug\lib</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>..\llvm_build\Debug\lib</AdditionalLibraryDirectories>
<AdditionalDependencies>LLVMJIT.lib;LLVMVectorize.lib;LLVMX86CodeGen.lib;LLVMX86Disassembler.lib;LLVMExecutionEngine.lib;LLVMAsmPrinter.lib;LLVMSelectionDAG.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMTarget.lib;LLVMX86Desc.lib;LLVMX86AsmPrinter.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMCore.lib;LLVMX86Utils.lib;LLVMMC.lib;LLVMX86Info.lib;LLVMSupport.lib;LLVMMCDisassembler.lib</AdditionalDependencies> <AdditionalDependencies>LLVMMCJIT.lib;LLVMRuntimeDyld.lib;LLVMVectorize.lib;LLVMX86CodeGen.lib;LLVMX86Disassembler.lib;LLVMExecutionEngine.lib;LLVMAsmPrinter.lib;LLVMSelectionDAG.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMTarget.lib;LLVMX86Desc.lib;LLVMX86AsmPrinter.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMCore.lib;LLVMX86Utils.lib;LLVMMC.lib;LLVMX86Info.lib;LLVMSupport.lib;LLVMMCDisassembler.lib</AdditionalDependencies>
</Lib> </Lib>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug - MemLeak|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug - MemLeak|x64'">
@ -777,10 +777,10 @@
</Link> </Link>
<Lib> <Lib>
<AdditionalLibraryDirectories>..\llvm_build\Release\lib</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>..\llvm_build\Release\lib</AdditionalLibraryDirectories>
<AdditionalDependencies>LLVMJIT.lib;LLVMVectorize.lib;LLVMX86CodeGen.lib;LLVMX86Disassembler.lib;LLVMExecutionEngine.lib;LLVMAsmPrinter.lib;LLVMSelectionDAG.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMTarget.lib;LLVMX86Desc.lib;LLVMX86AsmPrinter.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMCore.lib;LLVMX86Utils.lib;LLVMMC.lib;LLVMX86Info.lib;LLVMSupport.lib;LLVMMCDisassembler.lib</AdditionalDependencies> <AdditionalDependencies>LLVMMCJIT.lib;LLVMRuntimeDyld.lib;LLVMVectorize.lib;LLVMX86CodeGen.lib;LLVMX86Disassembler.lib;LLVMExecutionEngine.lib;LLVMAsmPrinter.lib;LLVMSelectionDAG.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMTarget.lib;LLVMX86Desc.lib;LLVMX86AsmPrinter.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMCore.lib;LLVMX86Utils.lib;LLVMMC.lib;LLVMX86Info.lib;LLVMSupport.lib;LLVMMCDisassembler.lib</AdditionalDependencies>
</Lib> </Lib>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
</Project> </Project>