Cache the optimized bitcode (note: this adds LLVMBitWriter as a dependency)

This commit is contained in:
Magnus Norddahl 2016-11-19 17:14:37 +01:00
parent d197ebca78
commit b4eb49678a
3 changed files with 190 additions and 109 deletions

View file

@ -294,7 +294,7 @@ endif()
set( LLVM_PRECOMPILED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../llvm" ) set( LLVM_PRECOMPILED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../llvm" )
if( NOT WIN32 ) if( NOT WIN32 )
set( LLVM_COMPONENTS core support asmparser asmprinter bitreader codegen ipo set( LLVM_COMPONENTS core support asmparser asmprinter bitreader bitwriter codegen ipo
irreader transformutils instrumentation profiledata runtimedyld irreader transformutils instrumentation profiledata runtimedyld
object instcombine linker analysis selectiondag scalaropts vectorize executionengine object instcombine linker analysis selectiondag scalaropts vectorize executionengine
mc mcdisassembler mcparser mcjit target x86asmprinter x86info x86desc x86utils x86codegen ) mc mcdisassembler mcparser mcjit target x86asmprinter x86info x86desc x86utils x86codegen )
@ -307,7 +307,7 @@ if( NOT WIN32 )
include_directories( ${LLVM_INCLUDE_DIRS} ) include_directories( ${LLVM_INCLUDE_DIRS} )
set( ZDOOM_LIBS ${ZDOOM_LIBS} ${llvm_libs} ) set( ZDOOM_LIBS ${ZDOOM_LIBS} ${llvm_libs} )
else() else()
set( LLVM_COMPONENTS core support asmparser asmprinter bitreader codegen passes ipo set( LLVM_COMPONENTS core support asmparser asmprinter bitreader bitwriter codegen passes ipo
irreader transformutils instrumentation profiledata debuginfocodeview runtimedyld irreader transformutils instrumentation profiledata debuginfocodeview runtimedyld
object instcombine linker analysis selectiondag scalaropts vectorize executionengine object instcombine linker analysis selectiondag scalaropts vectorize executionengine
mc mcdisassembler mcparser mcjit target x86asmprinter x86info x86desc x86utils x86codegen ) mc mcdisassembler mcparser mcjit target x86asmprinter x86info x86desc x86utils x86codegen )

View file

@ -75,6 +75,7 @@
#include <llvm/CodeGen/AsmPrinter.h> #include <llvm/CodeGen/AsmPrinter.h>
#include <llvm/MC/MCAsmInfo.h> #include <llvm/MC/MCAsmInfo.h>
#include <llvm/Target/TargetSubtargetInfo.h> #include <llvm/Target/TargetSubtargetInfo.h>
#include <llvm/Bitcode/ReaderWriter.h>
#if LLVM_VERSION_MAJOR < 3 || (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 8) #if LLVM_VERSION_MAJOR < 3 || (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 8)
#include <llvm/Support/FormattedStream.h> #include <llvm/Support/FormattedStream.h>

View file

@ -39,6 +39,7 @@
#include "x86.h" #include "x86.h"
#include "c_cvars.h" #include "c_cvars.h"
#include "version.h" #include "version.h"
#include "m_misc.h"
CUSTOM_CVAR(String, llvm_cpu, "auto", CVAR_ARCHIVE | CVAR_NOINITCALL) CUSTOM_CVAR(String, llvm_cpu, "auto", CVAR_ARCHIVE | CVAR_NOINITCALL)
{ {
@ -51,7 +52,9 @@ public:
LLVMProgram(); LLVMProgram();
void CreateModule(); void CreateModule();
void CreateEE(); std::string GetTargetCPU();
bool LoadCachedModule(int version, std::string targetCPU);
void CreateEE(int version, std::string targetCPU, bool optimize);
std::string GenerateAssembly(std::string cpuName); std::string GenerateAssembly(std::string cpuName);
std::string DumpModule(); std::string DumpModule();
void StopLogFatalErrors(); void StopLogFatalErrors();
@ -64,6 +67,8 @@ public:
llvm::ExecutionEngine *engine() { return mEngine.get(); } llvm::ExecutionEngine *engine() { return mEngine.get(); }
private: private:
void SaveCachedModule(llvm::Module *module, int version, std::string targetCPU);
FString GetDrawerCacheFilename(int version, FString cpu);
void *PointerToFunction(const char *name); void *PointerToFunction(const char *name);
llvm::TargetMachine *machine = nullptr; llvm::TargetMachine *machine = nullptr;
@ -121,6 +126,11 @@ LLVMDrawers *LLVMDrawers::Instance()
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
LLVMDrawersImpl::LLVMDrawersImpl() LLVMDrawersImpl::LLVMDrawersImpl()
{
int version = 1; // Increment this number if the drawer codegen is modified (forces recreation of the module).
std::string targetCPU = mProgram.GetTargetCPU();
bool loaded = mProgram.LoadCachedModule(version, targetCPU);
if (!loaded)
{ {
mProgram.CreateModule(); mProgram.CreateModule();
@ -198,8 +208,9 @@ LLVMDrawersImpl::LLVMDrawersImpl()
CodegenDrawTriangle("TriFillSubsector32_" + std::to_string(i), TriDrawVariant::FillSubsector, (TriBlendMode)i, true); CodegenDrawTriangle("TriFillSubsector32_" + std::to_string(i), TriDrawVariant::FillSubsector, (TriBlendMode)i, true);
} }
CodegenDrawTriangle("TriStencil", TriDrawVariant::Stencil, TriBlendMode::Copy, false); CodegenDrawTriangle("TriStencil", TriDrawVariant::Stencil, TriBlendMode::Copy, false);
}
mProgram.CreateEE(); mProgram.CreateEE(version, targetCPU, !loaded);
FillColumn = mProgram.GetProcAddress<void(const DrawColumnArgs *, const WorkerThreadData *)>("FillColumn"); FillColumn = mProgram.GetProcAddress<void(const DrawColumnArgs *, const WorkerThreadData *)>("FillColumn");
FillColumnAdd = mProgram.GetProcAddress<void(const DrawColumnArgs *, const WorkerThreadData *)>("FillColumnAdd"); FillColumnAdd = mProgram.GetProcAddress<void(const DrawColumnArgs *, const WorkerThreadData *)>("FillColumnAdd");
@ -603,12 +614,64 @@ void LLVMProgram::CreateModule()
mModule = std::make_unique<llvm::Module>("render", context()); mModule = std::make_unique<llvm::Module>("render", context());
} }
void LLVMProgram::CreateEE() bool LLVMProgram::LoadCachedModule(int version, std::string targetCPU)
{
FString filename = GetDrawerCacheFilename(version, targetCPU.c_str());
FILE *file = fopen(filename, "rb");
if (!file)
return false;
bool success = false;
std::string data;
fseek(file, 0, SEEK_END);
int length = ftell(file);
fseek(file, 0, SEEK_SET);
if (length > 0)
{
data.resize(length);
success = fread(&data[0], length, 1, file) == 1;
}
fclose(file);
if (!success)
return false;
auto result = llvm::parseBitcodeFile(llvm::MemoryBufferRef(data, filename.GetChars()), *mContext.get());
if (!result)
return false;
mModule = std::move(result.get());
return true;
}
void LLVMProgram::SaveCachedModule(llvm::Module *module, int version, std::string targetCPU)
{
std::string str;
llvm::raw_string_ostream stream(str);
llvm::WriteBitcodeToFile(module, stream);
std::string data = stream.str();
FString filename = GetDrawerCacheFilename(version, targetCPU.c_str());
FILE *file = fopen(filename, "wb");
if (file)
{
fwrite(data.data(), data.size(), 1, file);
fclose(file);
}
}
FString LLVMProgram::GetDrawerCacheFilename(int version, FString cpu)
{
FString path = M_GetCachePath(true);
FString filename;
filename.Format("%s/LLVMDrawers-%d-%s.bc", path.GetChars(), version, cpu.GetChars());
return filename;
}
std::string LLVMProgram::GetTargetCPU()
{ {
using namespace llvm; using namespace llvm;
std::string errorstring;
std::string mcpu = sys::getHostCPUName(); std::string mcpu = sys::getHostCPUName();
if (std::string(CPU.CPUString).find("G840") != std::string::npos && mcpu == "sandybridge") if (std::string(CPU.CPUString).find("G840") != std::string::npos && mcpu == "sandybridge")
mcpu = "westmere"; // Pentium G840 is misdetected as a sandy bridge CPU mcpu = "westmere"; // Pentium G840 is misdetected as a sandy bridge CPU
@ -618,13 +681,21 @@ void LLVMProgram::CreateEE()
mcpu = llvm_cpu; mcpu = llvm_cpu;
Printf("Overriding LLVM CPU target to %s\n", mcpu.c_str()); Printf("Overriding LLVM CPU target to %s\n", mcpu.c_str());
} }
return mcpu;
}
void LLVMProgram::CreateEE(int version, std::string targetCPU, bool optimize)
{
using namespace llvm;
std::string errorstring;
llvm::Module *module = mModule.get(); llvm::Module *module = mModule.get();
EngineBuilder engineBuilder(std::move(mModule)); EngineBuilder engineBuilder(std::move(mModule));
engineBuilder.setErrorStr(&errorstring); engineBuilder.setErrorStr(&errorstring);
engineBuilder.setOptLevel(CodeGenOpt::Aggressive); engineBuilder.setOptLevel(CodeGenOpt::Aggressive);
engineBuilder.setEngineKind(EngineKind::JIT); engineBuilder.setEngineKind(EngineKind::JIT);
engineBuilder.setMCPU(mcpu); engineBuilder.setMCPU(targetCPU);
machine = engineBuilder.selectTarget(); machine = engineBuilder.selectTarget();
if (!machine) if (!machine)
I_FatalError("Could not create LLVM target machine"); I_FatalError("Could not create LLVM target machine");
@ -638,6 +709,10 @@ void LLVMProgram::CreateEE()
Printf("LLVM target triple: %s\n", targetTriple.c_str()); Printf("LLVM target triple: %s\n", targetTriple.c_str());
Printf("LLVM target CPU: %s\n", cpuName.c_str()); Printf("LLVM target CPU: %s\n", cpuName.c_str());
if (optimize)
{
Printf("Optimizing drawers..\n");
module->setTargetTriple(targetTriple); module->setTargetTriple(targetTriple);
#if LLVM_VERSION_MAJOR < 3 || (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 8) #if LLVM_VERSION_MAJOR < 3 || (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 8)
module->setDataLayout(new DataLayout(*machine->getSubtargetImpl()->getDataLayout())); module->setDataLayout(new DataLayout(*machine->getSubtargetImpl()->getDataLayout()));
@ -675,6 +750,11 @@ void LLVMProgram::CreateEE()
// Run module passes: // Run module passes:
PerModulePasses.run(*module); PerModulePasses.run(*module);
SaveCachedModule(module, version, targetCPU);
}
Printf("Compiling drawers..\n");
// Create execution engine and generate machine code // Create execution engine and generate machine code
mEngine.reset(engineBuilder.create(machine)); mEngine.reset(engineBuilder.create(machine));
if (!mEngine) if (!mEngine)