* Notes:
*
******************************************************************************/
-#if defined(_WIN32)
-#pragma warning(disable: 4800 4146 4244 4267 4355 4996)
-#endif
+#include "jit_pch.hpp"
-#include "jit_api.h"
#include "JitManager.h"
+#include "jit_api.h"
#include "fetch_jit.h"
-#if defined(_WIN32)
-#include "llvm/ADT/Triple.h"
-#endif
-#include "llvm/IR/Function.h"
-#include "llvm/Support/DynamicLibrary.h"
-
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/SourceMgr.h"
-
-#include "llvm/Analysis/CFGPrinter.h"
-#include "llvm/IRReader/IRReader.h"
-
-#if LLVM_USE_INTEL_JITEVENTS
-#include "llvm/ExecutionEngine/JITEventListener.h"
-#endif
-
#include "core/state.h"
-#include "common/containers.hpp"
-#include "state_llvm.h"
+#include "gen_state_llvm.h"
#include <sstream>
#if defined(_WIN32)
#define INTEL_OUTPUT_DIR "c:\\Intel"
#define SWR_OUTPUT_DIR INTEL_OUTPUT_DIR "\\SWR"
#define JITTER_OUTPUT_DIR SWR_OUTPUT_DIR "\\Jitter"
+#endif // _WIN32
+
+#if defined(__APPLE__) || defined(FORCE_LINUX) || defined(__linux__) || defined(__gnu_linux__)
+#include <pwd.h>
+#include <sys/stat.h>
#endif
+
using namespace llvm;
+using namespace SwrJit;
//////////////////////////////////////////////////////////////////////////
/// @brief Contructor for JitManager.
/// @param simdWidth - SIMD width to be used in generated program.
-JitManager::JitManager(uint32_t simdWidth, const char *arch)
+JitManager::JitManager(uint32_t simdWidth, const char *arch, const char* core)
: mContext(), mBuilder(mContext), mIsModuleFinalized(true), mJitNumber(0), mVWidth(simdWidth), mArch(arch)
{
InitializeNativeTarget();
tOpts.AllowFPOpFusion = FPOpFusion::Fast;
tOpts.NoInfsFPMath = false;
tOpts.NoNaNsFPMath = false;
- tOpts.UnsafeFPMath = true;
-#if defined(_DEBUG)
-#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7
- tOpts.NoFramePointerElim = true;
-#endif
-#endif
+ tOpts.UnsafeFPMath = false;
//tOpts.PrintMachineCode = true;
- std::stringstream fnName("JitModule", std::ios_base::in | std::ios_base::out | std::ios_base::ate);
- fnName << mJitNumber++;
- std::unique_ptr<Module> newModule(new Module(fnName.str(), mContext));
- mpCurrentModule = newModule.get();
+ mCore = std::string(core);
+ std::transform(mCore.begin(), mCore.end(), mCore.begin(), ::tolower);
- auto &&EB = EngineBuilder(std::move(newModule));
- EB.setTargetOptions(tOpts);
- EB.setOptLevel(CodeGenOpt::Aggressive);
+ std::unique_ptr<Module> newModule(new Module("", mContext));
+ mpCurrentModule = newModule.get();
StringRef hostCPUName;
- // force JIT to use the same CPU arch as the rest of swr
- if(mArch.AVX512F())
- {
- assert(0 && "Implement AVX512 jitter");
- hostCPUName = sys::getHostCPUName();
- if (mVWidth == 0)
- {
- mVWidth = 16;
- }
- }
- else if(mArch.AVX2())
- {
- hostCPUName = StringRef("core-avx2");
- if (mVWidth == 0)
- {
- mVWidth = 8;
- }
- }
- else if(mArch.AVX())
- {
- if (mArch.F16C())
- {
- hostCPUName = StringRef("core-avx-i");
- }
- else
- {
- hostCPUName = StringRef("corei7-avx");
- }
- if (mVWidth == 0)
- {
- mVWidth = 8;
- }
- }
- else
- {
- hostCPUName = sys::getHostCPUName();
- if (mVWidth == 0)
- {
- mVWidth = 8; // 4?
- }
- }
-
- EB.setMCPU(hostCPUName);
+ hostCPUName = sys::getHostCPUName();
#if defined(_WIN32)
// Needed for MCJIT on windows
Triple hostTriple(sys::getProcessTriple());
- hostTriple.setObjectFormat(Triple::ELF);
+ hostTriple.setObjectFormat(Triple::COFF);
mpCurrentModule->setTargetTriple(hostTriple.getTriple());
#endif // _WIN32
- mpExec = EB.create();
+ auto optLevel = CodeGenOpt::Aggressive;
+
+ mpExec = EngineBuilder(std::move(newModule))
+ .setTargetOptions(tOpts)
+ .setOptLevel(optLevel)
+ .setMCPU(hostCPUName)
+ .create();
+
+ if (KNOB_JIT_ENABLE_CACHE)
+ {
+ mCache.Init(this, hostCPUName, optLevel);
+ mpExec->setObjectCache(&mCache);
+ }
#if LLVM_USE_INTEL_JITEVENTS
JITEventListener *vTune = JITEventListener::createIntelJITEventListener();
mInt8Ty = Type::getInt8Ty(mContext);
mInt32Ty = Type::getInt32Ty(mContext); // int type
mInt64Ty = Type::getInt64Ty(mContext); // int type
- mV4FP32Ty = StructType::get(mContext, std::vector<Type*>(4, mFP32Ty), false); // vector4 float type (represented as structure)
- mV4Int32Ty = StructType::get(mContext, std::vector<Type*>(4, mInt32Ty), false); // vector4 int type
// fetch function signature
+#if USE_SIMD16_SHADERS
+ // typedef void(__cdecl *PFN_FETCH_FUNC)(SWR_FETCH_CONTEXT& fetchInfo, simd16vertex& out);
+#else
// typedef void(__cdecl *PFN_FETCH_FUNC)(SWR_FETCH_CONTEXT& fetchInfo, simdvertex& out);
+#endif
std::vector<Type*> fsArgs;
+
+ // llvm5 is picky and does not take a void * type
+ fsArgs.push_back(PointerType::get(Gen_SWR_FETCH_CONTEXT(this), 0));
+
fsArgs.push_back(PointerType::get(Gen_SWR_FETCH_CONTEXT(this), 0));
+#if USE_SIMD16_SHADERS
+ fsArgs.push_back(PointerType::get(Gen_simd16vertex(this), 0));
+#else
fsArgs.push_back(PointerType::get(Gen_simdvertex(this), 0));
+#endif
mFetchShaderTy = FunctionType::get(Type::getVoidTy(mContext), fsArgs, false);
mSimtFP32Ty = VectorType::get(mFP32Ty, mVWidth);
mSimtInt32Ty = VectorType::get(mInt32Ty, mVWidth);
- mSimdVectorTy = StructType::get(mContext, std::vector<Type*>(4, mSimtFP32Ty), false);
- mSimdVectorInt32Ty = StructType::get(mContext, std::vector<Type*>(4, mSimtInt32Ty), false);
+ mSimdVectorTy = ArrayType::get(mSimtFP32Ty, 4);
+ mSimdVectorInt32Ty = ArrayType::get(mSimtInt32Ty, 4);
+
+#if USE_SIMD16_SHADERS
+ mSimd16FP32Ty = ArrayType::get(mSimtFP32Ty, 2);
+ mSimd16Int32Ty = ArrayType::get(mSimtInt32Ty, 2);
+
+ mSimd16VectorFP32Ty = ArrayType::get(mSimd16FP32Ty, 4);
+ mSimd16VectorInt32Ty = ArrayType::get(mSimd16Int32Ty, 4);
+#endif
#if defined(_WIN32)
// explicitly instantiate used symbols from potentially staticly linked libs
sys::DynamicLibrary::AddSymbol("exp2f", &exp2f);
#if defined(_WIN32)
if (KNOB_DUMP_SHADER_IR)
{
- CreateDirectory(INTEL_OUTPUT_DIR, NULL);
- CreateDirectory(SWR_OUTPUT_DIR, NULL);
- CreateDirectory(JITTER_OUTPUT_DIR, NULL);
+ CreateDirectoryPath(INTEL_OUTPUT_DIR);
+ CreateDirectoryPath(SWR_OUTPUT_DIR);
+ CreateDirectoryPath(JITTER_OUTPUT_DIR);
}
-
- ///@todo Figure out a better solution for this.
- // Redirect stdin, stdout, and stderr to attached console.
- freopen("CONIN$", "r", stdin);
- freopen("CONOUT$", "w", stdout);
- freopen("CONOUT$", "w", stderr);
#endif
}
{
SWR_ASSERT(mIsModuleFinalized == true && "Current module is not finalized!");
- std::stringstream fnName("JitModule", std::ios_base::in | std::ios_base::out | std::ios_base::ate);
- fnName << mJitNumber++;
- std::unique_ptr<Module> newModule(new Module(fnName.str(), mContext));
+ std::unique_ptr<Module> newModule(new Module("", mContext));
mpCurrentModule = newModule.get();
#if defined(_WIN32)
// Needed for MCJIT on windows
Triple hostTriple(sys::getProcessTriple());
- hostTriple.setObjectFormat(Triple::ELF);
+ hostTriple.setObjectFormat(Triple::COFF);
newModule->setTargetTriple(hostTriple.getTriple());
#endif // _WIN32
mIsModuleFinalized = false;
}
-//////////////////////////////////////////////////////////////////////////
-/// @brief Create new LLVM module from IR.
-bool JitManager::SetupModuleFromIR(const uint8_t *pIR)
+
+DIType* JitManager::CreateDebugStructType(StructType* pType, const std::string& name, DIFile* pFile, uint32_t lineNum,
+ const std::vector<std::pair<std::string, uint32_t>>& members)
{
- std::unique_ptr<MemoryBuffer> pMem = MemoryBuffer::getMemBuffer(StringRef((const char*)pIR), "");
+ DIBuilder builder(*mpCurrentModule);
+ SmallVector<Metadata*, 8> ElemTypes;
+ DataLayout DL = DataLayout(mpCurrentModule);
+ uint32_t size = DL.getTypeAllocSizeInBits(pType);
+ uint32_t alignment = DL.getABITypeAlignment(pType);
+ DINode::DIFlags flags = DINode::DIFlags::FlagPublic;
- SMDiagnostic Err;
- std::unique_ptr<Module> newModule = parseIR(pMem.get()->getMemBufferRef(), Err, mContext);
+ DICompositeType* pDIStructTy = builder.createStructType(pFile, name, pFile, lineNum, size, alignment,
+ flags, nullptr, builder.getOrCreateArray(ElemTypes));
- if (newModule == nullptr)
+ // Register mapping now to break loops (in case struct contains itself or pointers to itself)
+ mDebugStructMap[pType] = pDIStructTy;
+
+ uint32_t idx = 0;
+ for (auto& elem : pType->elements())
{
- SWR_ASSERT(0, "Parse failed! Check Err for details.");
- return false;
+ std::string name = members[idx].first;
+ uint32_t lineNum = members[idx].second;
+ size = DL.getTypeAllocSizeInBits(elem);
+ alignment = DL.getABITypeAlignment(elem);
+ uint32_t offset = DL.getStructLayout(pType)->getElementOffsetInBits(idx);
+ llvm::DIType* pDebugTy = GetDebugType(elem);
+ ElemTypes.push_back(builder.createMemberType(pDIStructTy, name, pFile, lineNum, size, alignment, offset, flags, pDebugTy));
+
+ idx++;
}
- mpCurrentModule = newModule.get();
-#if defined(_WIN32)
- // Needed for MCJIT on windows
- Triple hostTriple(sys::getProcessTriple());
- hostTriple.setObjectFormat(Triple::ELF);
- newModule->setTargetTriple(hostTriple.getTriple());
-#endif // _WIN32
+ pDIStructTy->replaceElements(builder.getOrCreateArray(ElemTypes));
+ return pDIStructTy;
+}
- mpExec->addModule(std::move(newModule));
- mIsModuleFinalized = false;
+DIType* JitManager::GetDebugArrayType(Type* pTy)
+{
+ DIBuilder builder(*mpCurrentModule);
+ DataLayout DL = DataLayout(mpCurrentModule);
+ ArrayType* pArrayTy = cast<ArrayType>(pTy);
+ uint32_t size = DL.getTypeAllocSizeInBits(pArrayTy);
+ uint32_t alignment = DL.getABITypeAlignment(pArrayTy);
+
+ SmallVector<Metadata*, 8> Elems;
+ Elems.push_back(builder.getOrCreateSubrange(0, pArrayTy->getNumElements()));
+ return builder.createArrayType(size, alignment, GetDebugType(pArrayTy->getElementType()), builder.getOrCreateArray(Elems));
+}
+
+// Create a DIType from llvm Type
+DIType* JitManager::GetDebugType(Type* pTy)
+{
+ DIBuilder builder(*mpCurrentModule);
+ Type::TypeID id = pTy->getTypeID();
+
+ switch (id)
+ {
+ case Type::VoidTyID: return builder.createUnspecifiedType("void"); break;
+ case Type::HalfTyID: return builder.createBasicType("float16", 16, dwarf::DW_ATE_float); break;
+ case Type::FloatTyID: return builder.createBasicType("float", 32, dwarf::DW_ATE_float); break;
+ case Type::DoubleTyID: return builder.createBasicType("double", 64, dwarf::DW_ATE_float); break;
+ case Type::IntegerTyID: return GetDebugIntegerType(pTy); break;
+ case Type::StructTyID: return GetDebugStructType(pTy); break;
+ case Type::ArrayTyID: return GetDebugArrayType(pTy); break;
+ case Type::PointerTyID: return builder.createPointerType(GetDebugType(pTy->getPointerElementType()), 64, 64); break;
+ case Type::VectorTyID: return GetDebugVectorType(pTy); break;
+ case Type::FunctionTyID: return GetDebugFunctionType(pTy); break;
+ default: SWR_ASSERT(false, "Unimplemented llvm type");
+ }
+ return nullptr;
+}
+
+// Create a DISubroutineType from an llvm FunctionType
+DIType* JitManager::GetDebugFunctionType(Type* pTy)
+{
+ SmallVector<Metadata*, 8> ElemTypes;
+ FunctionType* pFuncTy = cast<FunctionType>(pTy);
+ DIBuilder builder(*mpCurrentModule);
+
+ // Add result type
+ ElemTypes.push_back(GetDebugType(pFuncTy->getReturnType()));
+
+ // Add arguments
+ for (auto& param : pFuncTy->params())
+ {
+ ElemTypes.push_back(GetDebugType(param));
+ }
+
+ return builder.createSubroutineType(builder.getOrCreateTypeArray(ElemTypes));
+}
+
+DIType* JitManager::GetDebugIntegerType(Type* pTy)
+{
+ DIBuilder builder(*mpCurrentModule);
+ IntegerType* pIntTy = cast<IntegerType>(pTy);
+ switch (pIntTy->getBitWidth())
+ {
+ case 1: return builder.createBasicType("int1", 1, dwarf::DW_ATE_unsigned); break;
+ case 8: return builder.createBasicType("int8", 8, dwarf::DW_ATE_signed); break;
+ case 16: return builder.createBasicType("int16", 16, dwarf::DW_ATE_signed); break;
+ case 32: return builder.createBasicType("int", 32, dwarf::DW_ATE_signed); break;
+ case 64: return builder.createBasicType("int64", 64, dwarf::DW_ATE_signed); break;
+ case 128: return builder.createBasicType("int128", 128, dwarf::DW_ATE_signed); break;
+ default: SWR_ASSERT(false, "Unimplemented integer bit width");
+ }
+ return nullptr;
+}
+
+DIType* JitManager::GetDebugVectorType(Type* pTy)
+{
+ DIBuilder builder(*mpCurrentModule);
+ VectorType* pVecTy = cast<VectorType>(pTy);
+ DataLayout DL = DataLayout(mpCurrentModule);
+ uint32_t size = DL.getTypeAllocSizeInBits(pVecTy);
+ uint32_t alignment = DL.getABITypeAlignment(pVecTy);
+ SmallVector<Metadata*, 1> Elems;
+ Elems.push_back(builder.getOrCreateSubrange(0, pVecTy->getVectorNumElements()));
+
+ return builder.createVectorType(size, alignment, GetDebugType(pVecTy->getVectorElementType()), builder.getOrCreateArray(Elems));
- return true;
}
//////////////////////////////////////////////////////////////////////////
-/// @brief Dump function to file.
-void JitManager::DumpToFile(Function *f, const char *fileName)
+/// @brief Dump function x86 assembly to file.
+/// @note This should only be called after the module has been jitted to x86 and the
+/// module will not be further accessed.
+void JitManager::DumpAsm(Function* pFunction, const char* fileName)
{
if (KNOB_DUMP_SHADER_IR)
{
+
#if defined(_WIN32)
DWORD pid = GetCurrentProcessId();
- TCHAR procname[MAX_PATH];
- GetModuleFileName(NULL, procname, MAX_PATH);
+ char procname[MAX_PATH];
+ GetModuleFileNameA(NULL, procname, MAX_PATH);
const char* pBaseName = strrchr(procname, '\\');
std::stringstream outDir;
outDir << JITTER_OUTPUT_DIR << pBaseName << "_" << pid << std::ends;
- CreateDirectory(outDir.str().c_str(), NULL);
+ CreateDirectoryPath(outDir.str().c_str());
#endif
+ std::error_code EC;
+ Module* pModule = pFunction->getParent();
+ const char *funcName = pFunction->getName().data();
+ char fName[256];
+#if defined(_WIN32)
+ sprintf(fName, "%s\\%s.%s.asm", outDir.str().c_str(), funcName, fileName);
+#else
+ sprintf(fName, "%s.%s.asm", funcName, fileName);
+#endif
+
+ raw_fd_ostream filestream(fName, EC, llvm::sys::fs::F_None);
+
+ legacy::PassManager* pMPasses = new legacy::PassManager();
+ auto* pTarget = mpExec->getTargetMachine();
+ pTarget->Options.MCOptions.AsmVerbose = true;
+ pTarget->addPassesToEmitFile(*pMPasses, filestream, TargetMachine::CGFT_AssemblyFile);
+ pMPasses->run(*pModule);
+ delete pMPasses;
+ pTarget->Options.MCOptions.AsmVerbose = false;
+ }
+}
+
+std::string JitManager::GetOutputDir()
+{
+#if defined(_WIN32)
+ DWORD pid = GetCurrentProcessId();
+ char procname[MAX_PATH];
+ GetModuleFileNameA(NULL, procname, MAX_PATH);
+ const char* pBaseName = strrchr(procname, '\\');
+ std::stringstream outDir;
+ outDir << JITTER_OUTPUT_DIR << pBaseName << "_" << pid;
+ CreateDirectoryPath(outDir.str().c_str());
+ return outDir.str();
+#endif
+ return "";
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief Dump function to file.
+void JitManager::DumpToFile(Module *M, const char *fileName)
+{
+ if (KNOB_DUMP_SHADER_IR)
+ {
+ std::string outDir = GetOutputDir();
+
+ std::error_code EC;
+ const char *funcName = M->getName().data();
+ char fName[256];
+#if defined(_WIN32)
+ sprintf(fName, "%s\\%s.%s.ll", outDir.c_str(), funcName, fileName);
+#else
+ sprintf(fName, "%s.%s.ll", funcName, fileName);
+#endif
+ raw_fd_ostream fd(fName, EC, llvm::sys::fs::F_None);
+ M->print(fd, nullptr);
+ fd.flush();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief Dump function to file.
+void JitManager::DumpToFile(Function *f, const char *fileName)
+{
+ if (KNOB_DUMP_SHADER_IR)
+ {
+ std::string outDir = GetOutputDir();
+
std::error_code EC;
const char *funcName = f->getName().data();
char fName[256];
#if defined(_WIN32)
- sprintf(fName, "%s\\%s.%s.ll", outDir.str().c_str(), funcName, fileName);
+ sprintf(fName, "%s\\%s.%s.ll", outDir.c_str(), funcName, fileName);
#else
sprintf(fName, "%s.%s.ll", funcName, fileName);
#endif
raw_fd_ostream fd(fName, EC, llvm::sys::fs::F_None);
- Module* pModule = f->getParent();
- pModule->print(fd, nullptr);
+ f->print(fd, nullptr);
#if defined(_WIN32)
- sprintf(fName, "%s\\cfg.%s.%s.dot", outDir.str().c_str(), funcName, fileName);
+ sprintf(fName, "%s\\cfg.%s.%s.dot", outDir.c_str(), funcName, fileName);
#else
sprintf(fName, "cfg.%s.%s.dot", funcName, fileName);
#endif
extern "C"
{
+ bool g_DllActive = true;
+
//////////////////////////////////////////////////////////////////////////
/// @brief Create JIT context.
/// @param simdWidth - SIMD width to be used in generated program.
- HANDLE JITCALL JitCreateContext(uint32_t targetSimdWidth, const char* arch)
+ HANDLE JITCALL JitCreateContext(uint32_t targetSimdWidth, const char* arch, const char* core)
{
- return new JitManager(targetSimdWidth, arch);
+ return new JitManager(targetSimdWidth, arch, core);
}
//////////////////////////////////////////////////////////////////////////
/// @brief Destroy JIT context.
void JITCALL JitDestroyContext(HANDLE hJitContext)
{
- delete reinterpret_cast<JitManager*>(hJitContext);
+ if (g_DllActive)
+ {
+ delete reinterpret_cast<JitManager*>(hJitContext);
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// JitCache
+//////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////
+/// JitCacheFileHeader
+//////////////////////////////////////////////////////////////////////////
+struct JitCacheFileHeader
+{
+ void Init(
+ uint32_t llCRC,
+ uint32_t objCRC,
+ const std::string& moduleID,
+ const std::string& cpu,
+ uint32_t optLevel,
+ uint64_t objSize)
+ {
+ m_objSize = objSize;
+ m_llCRC = llCRC;
+ m_objCRC = objCRC;
+ strncpy(m_ModuleID, moduleID.c_str(), JC_STR_MAX_LEN - 1);
+ m_ModuleID[JC_STR_MAX_LEN - 1] = 0;
+ strncpy(m_Cpu, cpu.c_str(), JC_STR_MAX_LEN - 1);
+ m_Cpu[JC_STR_MAX_LEN - 1] = 0;
+ m_optLevel = optLevel;
+ }
+
+
+ bool IsValid(uint32_t llCRC, const std::string& moduleID, const std::string& cpu, uint32_t optLevel)
+ {
+ if ((m_MagicNumber != JC_MAGIC_NUMBER) ||
+ (m_llCRC != llCRC) ||
+ (m_platformKey != JC_PLATFORM_KEY) ||
+ (m_optLevel != optLevel))
+ {
+ return false;
+ }
+
+ m_ModuleID[JC_STR_MAX_LEN - 1] = 0;
+ if (strncmp(moduleID.c_str(), m_ModuleID, JC_STR_MAX_LEN - 1))
+ {
+ return false;
+ }
+
+ m_Cpu[JC_STR_MAX_LEN - 1] = 0;
+ if (strncmp(cpu.c_str(), m_Cpu, JC_STR_MAX_LEN - 1))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ uint64_t GetObjectSize() const { return m_objSize; }
+ uint64_t GetObjectCRC() const { return m_objCRC; }
+
+private:
+ static const uint64_t JC_MAGIC_NUMBER = 0xfedcba9876543211ULL + 3;
+ static const size_t JC_STR_MAX_LEN = 32;
+ static const uint32_t JC_PLATFORM_KEY =
+ (LLVM_VERSION_MAJOR << 24) |
+ (LLVM_VERSION_MINOR << 16) |
+ (LLVM_VERSION_PATCH << 8) |
+ ((sizeof(void*) > sizeof(uint32_t)) ? 1 : 0);
+
+ uint64_t m_MagicNumber = JC_MAGIC_NUMBER;
+ uint64_t m_objSize = 0;
+ uint32_t m_llCRC = 0;
+ uint32_t m_platformKey = JC_PLATFORM_KEY;
+ uint32_t m_objCRC = 0;
+ uint32_t m_optLevel = 0;
+ char m_ModuleID[JC_STR_MAX_LEN] = {};
+ char m_Cpu[JC_STR_MAX_LEN] = {};
+};
+
+static inline uint32_t ComputeModuleCRC(const llvm::Module* M)
+{
+ std::string bitcodeBuffer;
+ raw_string_ostream bitcodeStream(bitcodeBuffer);
+
+ llvm::WriteBitcodeToFile(M, bitcodeStream);
+ //M->print(bitcodeStream, nullptr, false);
+
+ bitcodeStream.flush();
+
+ return ComputeCRC(0, bitcodeBuffer.data(), bitcodeBuffer.size());
+}
+
+/// constructor
+JitCache::JitCache()
+{
+#if defined(__APPLE__) || defined(FORCE_LINUX) || defined(__linux__) || defined(__gnu_linux__)
+ if (strncmp(KNOB_JIT_CACHE_DIR.c_str(), "~/", 2) == 0) {
+ char *homedir;
+ if (!(homedir = getenv("HOME"))) {
+ homedir = getpwuid(getuid())->pw_dir;
+ }
+ mCacheDir = homedir;
+ mCacheDir += (KNOB_JIT_CACHE_DIR.c_str() + 1);
+ } else
+#endif
+ {
+ mCacheDir = KNOB_JIT_CACHE_DIR;
+ }
+}
+
+int ExecUnhookedProcess(const std::string& CmdLine, std::string* pStdOut, std::string* pStdErr)
+{
+ static const char *g_pEnv = "RASTY_DISABLE_HOOK=1\0";
+
+ return ExecCmd(CmdLine, g_pEnv, pStdOut, pStdErr);
+}
+
+
+/// notifyObjectCompiled - Provides a pointer to compiled code for Module M.
+void JitCache::notifyObjectCompiled(const llvm::Module *M, llvm::MemoryBufferRef Obj)
+{
+ const std::string& moduleID = M->getModuleIdentifier();
+ if (!moduleID.length())
+ {
+ return;
+ }
+
+ if (!llvm::sys::fs::exists(mCacheDir.str()) &&
+ llvm::sys::fs::create_directories(mCacheDir.str()))
+ {
+ SWR_INVALID("Unable to create directory: %s", mCacheDir.c_str());
+ return;
+ }
+
+ JitCacheFileHeader header;
+
+ llvm::SmallString<MAX_PATH> filePath = mCacheDir;
+ llvm::sys::path::append(filePath, moduleID);
+
+ llvm::SmallString<MAX_PATH> objPath = filePath;
+ objPath += JIT_OBJ_EXT;
+
+ {
+ std::error_code err;
+ llvm::raw_fd_ostream fileObj(objPath.c_str(), err, llvm::sys::fs::F_None);
+ fileObj << Obj.getBuffer();
+ fileObj.flush();
+ }
+
+
+ {
+ std::error_code err;
+ llvm::raw_fd_ostream fileObj(filePath.c_str(), err, llvm::sys::fs::F_None);
+
+ uint32_t objcrc = ComputeCRC(0, Obj.getBufferStart(), Obj.getBufferSize());
+
+ header.Init(mCurrentModuleCRC, objcrc, moduleID, mCpu, mOptLevel, Obj.getBufferSize());
+
+ fileObj.write((const char*)&header, sizeof(header));
+ fileObj.flush();
}
}
+
+/// Returns a pointer to a newly allocated MemoryBuffer that contains the
+/// object which corresponds with Module M, or 0 if an object is not
+/// available.
+std::unique_ptr<llvm::MemoryBuffer> JitCache::getObject(const llvm::Module* M)
+{
+ const std::string& moduleID = M->getModuleIdentifier();
+ mCurrentModuleCRC = ComputeModuleCRC(M);
+
+ if (!moduleID.length())
+ {
+ return nullptr;
+ }
+
+ if (!llvm::sys::fs::exists(mCacheDir))
+ {
+ return nullptr;
+ }
+
+ llvm::SmallString<MAX_PATH> filePath = mCacheDir;
+ llvm::sys::path::append(filePath, moduleID);
+
+ llvm::SmallString<MAX_PATH> objFilePath = filePath;
+ objFilePath += JIT_OBJ_EXT;
+
+ FILE* fpObjIn = nullptr;
+ FILE* fpIn = fopen(filePath.c_str(), "rb");
+ if (!fpIn)
+ {
+ return nullptr;
+ }
+
+ std::unique_ptr<llvm::MemoryBuffer> pBuf = nullptr;
+ do
+ {
+ JitCacheFileHeader header;
+ if (!fread(&header, sizeof(header), 1, fpIn))
+ {
+ break;
+ }
+
+ if (!header.IsValid(mCurrentModuleCRC, moduleID, mCpu, mOptLevel))
+ {
+ break;
+ }
+
+ fpObjIn = fopen(objFilePath.c_str(), "rb");
+ if (!fpObjIn)
+ {
+ break;
+ }
+
+#if LLVM_VERSION_MAJOR < 6
+ pBuf = llvm::MemoryBuffer::getNewUninitMemBuffer(size_t(header.GetObjectSize()));
+#else
+ pBuf = llvm::WritableMemoryBuffer::getNewUninitMemBuffer(size_t(header.GetObjectSize()));
+#endif
+ if (!fread(const_cast<char*>(pBuf->getBufferStart()), header.GetObjectSize(), 1, fpObjIn))
+ {
+ pBuf = nullptr;
+ break;
+ }
+
+ if (header.GetObjectCRC() != ComputeCRC(0, pBuf->getBufferStart(), pBuf->getBufferSize()))
+ {
+ SWR_TRACE("Invalid object cache file, ignoring: %s", filePath.c_str());
+ pBuf = nullptr;
+ break;
+ }
+
+ }
+ while (0);
+
+ fclose(fpIn);
+
+ if (fpObjIn)
+ {
+ fclose(fpObjIn);
+ }
+
+
+ return pBuf;
+}