Home | History | Annotate | Download | only in jitter
      1 /****************************************************************************
      2 * Copyright (C) 2014-2015 Intel Corporation.   All Rights Reserved.
      3 *
      4 * Permission is hereby granted, free of charge, to any person obtaining a
      5 * copy of this software and associated documentation files (the "Software"),
      6 * to deal in the Software without restriction, including without limitation
      7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 * and/or sell copies of the Software, and to permit persons to whom the
      9 * Software is furnished to do so, subject to the following conditions:
     10 *
     11 * The above copyright notice and this permission notice (including the next
     12 * paragraph) shall be included in all copies or substantial portions of the
     13 * Software.
     14 *
     15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     21 * IN THE SOFTWARE.
     22 *
     23 * @file JitManager.cpp
     24 *
     25 * @brief Implementation if the Jit Manager.
     26 *
     27 * Notes:
     28 *
     29 ******************************************************************************/
     30 #include "jit_pch.hpp"
     31 
     32 #include "JitManager.h"
     33 #include "jit_api.h"
     34 #include "fetch_jit.h"
     35 
     36 #include "core/state.h"
     37 
     38 #include "gen_state_llvm.h"
     39 
     40 #include <sstream>
     41 #if defined(_WIN32)
     42 #include <psapi.h>
     43 #include <cstring>
     44 
     45 #define INTEL_OUTPUT_DIR "c:\\Intel"
     46 #define SWR_OUTPUT_DIR INTEL_OUTPUT_DIR "\\SWR"
     47 #define JITTER_OUTPUT_DIR SWR_OUTPUT_DIR "\\Jitter"
     48 #endif // _WIN32
     49 
     50 #if defined(__APPLE__) || defined(FORCE_LINUX) || defined(__linux__) || defined(__gnu_linux__)
     51 #include <pwd.h>
     52 #include <sys/stat.h>
     53 #endif
     54 
     55 
     56 using namespace llvm;
     57 using namespace SwrJit;
     58 
     59 //////////////////////////////////////////////////////////////////////////
     60 /// @brief Contructor for JitManager.
     61 /// @param simdWidth - SIMD width to be used in generated program.
     62 JitManager::JitManager(uint32_t simdWidth, const char *arch, const char* core)
     63     : mContext(), mBuilder(mContext), mIsModuleFinalized(true), mJitNumber(0), mVWidth(simdWidth), mArch(arch)
     64 {
     65     InitializeNativeTarget();
     66     InitializeNativeTargetAsmPrinter();
     67     InitializeNativeTargetDisassembler();
     68 
     69     TargetOptions    tOpts;
     70     tOpts.AllowFPOpFusion = FPOpFusion::Fast;
     71     tOpts.NoInfsFPMath = false;
     72     tOpts.NoNaNsFPMath = false;
     73     tOpts.UnsafeFPMath = false;
     74 #if defined(_DEBUG)
     75 #if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7
     76     tOpts.NoFramePointerElim = true;
     77 #endif
     78 #endif
     79 
     80     //tOpts.PrintMachineCode    = true;
     81 
     82     mCore = std::string(core);
     83     std::transform(mCore.begin(), mCore.end(), mCore.begin(), ::tolower);
     84 
     85     std::unique_ptr<Module> newModule(new Module("", mContext));
     86     mpCurrentModule = newModule.get();
     87 
     88     StringRef hostCPUName;
     89 
     90     hostCPUName = sys::getHostCPUName();
     91 
     92 #if defined(_WIN32)
     93     // Needed for MCJIT on windows
     94     Triple hostTriple(sys::getProcessTriple());
     95     hostTriple.setObjectFormat(Triple::COFF);
     96     mpCurrentModule->setTargetTriple(hostTriple.getTriple());
     97 #endif // _WIN32
     98 
     99     auto optLevel = CodeGenOpt::Aggressive;
    100 
    101     mpExec = EngineBuilder(std::move(newModule))
    102         .setTargetOptions(tOpts)
    103         .setOptLevel(optLevel)
    104         .setMCPU(hostCPUName)
    105         .create();
    106 
    107     if (KNOB_JIT_ENABLE_CACHE)
    108     {
    109         mCache.Init(this, hostCPUName, optLevel);
    110         mpExec->setObjectCache(&mCache);
    111     }
    112 
    113 #if LLVM_USE_INTEL_JITEVENTS
    114     JITEventListener *vTune = JITEventListener::createIntelJITEventListener();
    115     mpExec->RegisterJITEventListener(vTune);
    116 #endif
    117 
    118     mFP32Ty = Type::getFloatTy(mContext);   // float type
    119     mInt8Ty = Type::getInt8Ty(mContext);
    120     mInt32Ty = Type::getInt32Ty(mContext);   // int type
    121     mInt64Ty = Type::getInt64Ty(mContext);   // int type
    122 
    123     // fetch function signature
    124 #if USE_SIMD16_SHADERS
    125     // typedef void(__cdecl *PFN_FETCH_FUNC)(SWR_FETCH_CONTEXT& fetchInfo, simd16vertex& out);
    126 #else
    127     // typedef void(__cdecl *PFN_FETCH_FUNC)(SWR_FETCH_CONTEXT& fetchInfo, simdvertex& out);
    128 #endif
    129     std::vector<Type*> fsArgs;
    130 
    131     // llvm5 is picky and does not take a void * type
    132     fsArgs.push_back(PointerType::get(Gen_SWR_FETCH_CONTEXT(this), 0));
    133 
    134     fsArgs.push_back(PointerType::get(Gen_SWR_FETCH_CONTEXT(this), 0));
    135 #if USE_SIMD16_SHADERS
    136     fsArgs.push_back(PointerType::get(Gen_simd16vertex(this), 0));
    137 #else
    138     fsArgs.push_back(PointerType::get(Gen_simdvertex(this), 0));
    139 #endif
    140 
    141     mFetchShaderTy = FunctionType::get(Type::getVoidTy(mContext), fsArgs, false);
    142 
    143     mSimtFP32Ty = VectorType::get(mFP32Ty, mVWidth);
    144     mSimtInt32Ty = VectorType::get(mInt32Ty, mVWidth);
    145 
    146     mSimdVectorTy = ArrayType::get(mSimtFP32Ty, 4);
    147     mSimdVectorInt32Ty = ArrayType::get(mSimtInt32Ty, 4);
    148 
    149 #if USE_SIMD16_SHADERS
    150     mSimd16FP32Ty = ArrayType::get(mSimtFP32Ty, 2);
    151     mSimd16Int32Ty = ArrayType::get(mSimtInt32Ty, 2);
    152 
    153     mSimd16VectorFP32Ty = ArrayType::get(mSimd16FP32Ty, 4);
    154     mSimd16VectorInt32Ty = ArrayType::get(mSimd16Int32Ty, 4);
    155 
    156 #endif
    157 #if defined(_WIN32)
    158     // explicitly instantiate used symbols from potentially staticly linked libs
    159     sys::DynamicLibrary::AddSymbol("exp2f", &exp2f);
    160     sys::DynamicLibrary::AddSymbol("log2f", &log2f);
    161     sys::DynamicLibrary::AddSymbol("sinf", &sinf);
    162     sys::DynamicLibrary::AddSymbol("cosf", &cosf);
    163     sys::DynamicLibrary::AddSymbol("powf", &powf);
    164 #endif
    165 
    166 #if defined(_WIN32)
    167     if (KNOB_DUMP_SHADER_IR)
    168     {
    169         CreateDirectoryPath(INTEL_OUTPUT_DIR);
    170         CreateDirectoryPath(SWR_OUTPUT_DIR);
    171         CreateDirectoryPath(JITTER_OUTPUT_DIR);
    172     }
    173 #endif
    174 }
    175 
    176 //////////////////////////////////////////////////////////////////////////
    177 /// @brief Create new LLVM module.
    178 void JitManager::SetupNewModule()
    179 {
    180     SWR_ASSERT(mIsModuleFinalized == true && "Current module is not finalized!");
    181 
    182     std::unique_ptr<Module> newModule(new Module("", mContext));
    183     mpCurrentModule = newModule.get();
    184 #if defined(_WIN32)
    185     // Needed for MCJIT on windows
    186     Triple hostTriple(sys::getProcessTriple());
    187     hostTriple.setObjectFormat(Triple::COFF);
    188     newModule->setTargetTriple(hostTriple.getTriple());
    189 #endif // _WIN32
    190 
    191     mpExec->addModule(std::move(newModule));
    192     mIsModuleFinalized = false;
    193 }
    194 
    195 
    196 DIType* JitManager::CreateDebugStructType(StructType* pType, const std::string& name, DIFile* pFile, uint32_t lineNum,
    197     const std::vector<std::pair<std::string, uint32_t>>& members)
    198 {
    199     DIBuilder builder(*mpCurrentModule);
    200     SmallVector<Metadata*, 8> ElemTypes;
    201     DataLayout DL = DataLayout(mpCurrentModule);
    202     uint32_t size = DL.getTypeAllocSizeInBits(pType);
    203     uint32_t alignment = DL.getABITypeAlignment(pType);
    204     DINode::DIFlags flags = DINode::DIFlags::FlagPublic;
    205 
    206     DICompositeType* pDIStructTy = builder.createStructType(pFile, name, pFile, lineNum, size, alignment,
    207         flags, nullptr, builder.getOrCreateArray(ElemTypes));
    208 
    209     // Register mapping now to break loops (in case struct contains itself or pointers to itself)
    210     mDebugStructMap[pType] = pDIStructTy;
    211 
    212     uint32_t idx = 0;
    213     for (auto& elem : pType->elements())
    214     {
    215         std::string name = members[idx].first;
    216         uint32_t lineNum = members[idx].second;
    217         size = DL.getTypeAllocSizeInBits(elem);
    218         alignment = DL.getABITypeAlignment(elem);
    219         uint32_t offset = DL.getStructLayout(pType)->getElementOffsetInBits(idx);
    220         llvm::DIType* pDebugTy = GetDebugType(elem);
    221         ElemTypes.push_back(builder.createMemberType(pDIStructTy, name, pFile, lineNum, size, alignment, offset, flags, pDebugTy));
    222 
    223         idx++;
    224     }
    225 
    226     pDIStructTy->replaceElements(builder.getOrCreateArray(ElemTypes));
    227     return pDIStructTy;
    228 }
    229 
    230 DIType* JitManager::GetDebugArrayType(Type* pTy)
    231 {
    232     DIBuilder builder(*mpCurrentModule);
    233     DataLayout DL = DataLayout(mpCurrentModule);
    234     ArrayType* pArrayTy = cast<ArrayType>(pTy);
    235     uint32_t size = DL.getTypeAllocSizeInBits(pArrayTy);
    236     uint32_t alignment = DL.getABITypeAlignment(pArrayTy);
    237 
    238     SmallVector<Metadata*, 8> Elems;
    239     Elems.push_back(builder.getOrCreateSubrange(0, pArrayTy->getNumElements()));
    240     return builder.createArrayType(size, alignment, GetDebugType(pArrayTy->getElementType()), builder.getOrCreateArray(Elems));
    241 }
    242 
    243 // Create a DIType from llvm Type
    244 DIType* JitManager::GetDebugType(Type* pTy)
    245 {
    246     DIBuilder builder(*mpCurrentModule);
    247     Type::TypeID id = pTy->getTypeID();
    248 
    249     switch (id)
    250     {
    251     case Type::VoidTyID: return builder.createUnspecifiedType("void"); break;
    252 #if LLVM_VERSION_MAJOR >= 4
    253     case Type::HalfTyID: return builder.createBasicType("float16", 16, dwarf::DW_ATE_float); break;
    254     case Type::FloatTyID: return builder.createBasicType("float", 32, dwarf::DW_ATE_float); break;
    255     case Type::DoubleTyID: return builder.createBasicType("double", 64, dwarf::DW_ATE_float); break;
    256 #else
    257     case Type::HalfTyID: return builder.createBasicType("float16", 16, 0, dwarf::DW_ATE_float); break;
    258     case Type::FloatTyID: return builder.createBasicType("float", 32, 0, dwarf::DW_ATE_float); break;
    259     case Type::DoubleTyID: return builder.createBasicType("double", 64, 0, dwarf::DW_ATE_float); break;
    260 #endif
    261     case Type::IntegerTyID: return GetDebugIntegerType(pTy); break;
    262     case Type::StructTyID: return GetDebugStructType(pTy); break;
    263     case Type::ArrayTyID: return GetDebugArrayType(pTy); break;
    264     case Type::PointerTyID: return builder.createPointerType(GetDebugType(pTy->getPointerElementType()), 64, 64); break;
    265     case Type::VectorTyID: return GetDebugVectorType(pTy); break;
    266     case Type::FunctionTyID: return GetDebugFunctionType(pTy); break;
    267     default: SWR_ASSERT(false, "Unimplemented llvm type");
    268     }
    269     return nullptr;
    270 }
    271 
    272 // Create a DISubroutineType from an llvm FunctionType
    273 DIType* JitManager::GetDebugFunctionType(Type* pTy)
    274 {
    275     SmallVector<Metadata*, 8> ElemTypes;
    276     FunctionType* pFuncTy = cast<FunctionType>(pTy);
    277     DIBuilder builder(*mpCurrentModule);
    278 
    279     // Add result type
    280     ElemTypes.push_back(GetDebugType(pFuncTy->getReturnType()));
    281 
    282     // Add arguments
    283     for (auto& param : pFuncTy->params())
    284     {
    285         ElemTypes.push_back(GetDebugType(param));
    286     }
    287 
    288     return builder.createSubroutineType(builder.getOrCreateTypeArray(ElemTypes));
    289 }
    290 
    291 DIType* JitManager::GetDebugIntegerType(Type* pTy)
    292 {
    293     DIBuilder builder(*mpCurrentModule);
    294     IntegerType* pIntTy = cast<IntegerType>(pTy);
    295     switch (pIntTy->getBitWidth())
    296     {
    297 #if LLVM_VERSION_MAJOR >= 4
    298     case 1: return builder.createBasicType("int1", 1, dwarf::DW_ATE_unsigned); break;
    299     case 8: return builder.createBasicType("int8", 8, dwarf::DW_ATE_signed); break;
    300     case 16: return builder.createBasicType("int16", 16, dwarf::DW_ATE_signed); break;
    301     case 32: return builder.createBasicType("int", 32, dwarf::DW_ATE_signed); break;
    302     case 64: return builder.createBasicType("int64", 64, dwarf::DW_ATE_signed); break;
    303 #else
    304     case 1: return builder.createBasicType("int1", 1, 0, dwarf::DW_ATE_unsigned); break;
    305     case 8: return builder.createBasicType("int8", 8, 0, dwarf::DW_ATE_signed); break;
    306     case 16: return builder.createBasicType("int16", 16, 0, dwarf::DW_ATE_signed); break;
    307     case 32: return builder.createBasicType("int", 32, 0, dwarf::DW_ATE_signed); break;
    308     case 64: return builder.createBasicType("int64", 64, 0, dwarf::DW_ATE_signed); break;
    309 #endif
    310     default: SWR_ASSERT(false, "Unimplemented integer bit width");
    311     }
    312     return nullptr;
    313 }
    314 
    315 DIType* JitManager::GetDebugVectorType(Type* pTy)
    316 {
    317     DIBuilder builder(*mpCurrentModule);
    318     VectorType* pVecTy = cast<VectorType>(pTy);
    319     DataLayout DL = DataLayout(mpCurrentModule);
    320     uint32_t size = DL.getTypeAllocSizeInBits(pVecTy);
    321     uint32_t alignment = DL.getABITypeAlignment(pVecTy);
    322     SmallVector<Metadata*, 1> Elems;
    323     Elems.push_back(builder.getOrCreateSubrange(0, pVecTy->getVectorNumElements()));
    324 
    325     return builder.createVectorType(size, alignment, GetDebugType(pVecTy->getVectorElementType()), builder.getOrCreateArray(Elems));
    326 
    327 }
    328 
    329 //////////////////////////////////////////////////////////////////////////
    330 /// @brief Dump function x86 assembly to file.
    331 /// @note This should only be called after the module has been jitted to x86 and the
    332 ///       module will not be further accessed.
    333 void JitManager::DumpAsm(Function* pFunction, const char* fileName)
    334 {
    335     if (KNOB_DUMP_SHADER_IR)
    336     {
    337 
    338 #if defined(_WIN32)
    339         DWORD pid = GetCurrentProcessId();
    340         char procname[MAX_PATH];
    341         GetModuleFileNameA(NULL, procname, MAX_PATH);
    342         const char* pBaseName = strrchr(procname, '\\');
    343         std::stringstream outDir;
    344         outDir << JITTER_OUTPUT_DIR << pBaseName << "_" << pid << std::ends;
    345         CreateDirectoryPath(outDir.str().c_str());
    346 #endif
    347 
    348         std::error_code EC;
    349         Module* pModule = pFunction->getParent();
    350         const char *funcName = pFunction->getName().data();
    351         char fName[256];
    352 #if defined(_WIN32)
    353         sprintf(fName, "%s\\%s.%s.asm", outDir.str().c_str(), funcName, fileName);
    354 #else
    355         sprintf(fName, "%s.%s.asm", funcName, fileName);
    356 #endif
    357 
    358         raw_fd_ostream filestream(fName, EC, llvm::sys::fs::F_None);
    359 
    360         legacy::PassManager* pMPasses = new legacy::PassManager();
    361         auto* pTarget = mpExec->getTargetMachine();
    362         pTarget->Options.MCOptions.AsmVerbose = true;
    363         pTarget->addPassesToEmitFile(*pMPasses, filestream, TargetMachine::CGFT_AssemblyFile);
    364         pMPasses->run(*pModule);
    365         delete pMPasses;
    366         pTarget->Options.MCOptions.AsmVerbose = false;
    367     }
    368 }
    369 
    370 std::string JitManager::GetOutputDir()
    371 {
    372 #if defined(_WIN32)
    373     DWORD pid = GetCurrentProcessId();
    374     char procname[MAX_PATH];
    375     GetModuleFileNameA(NULL, procname, MAX_PATH);
    376     const char* pBaseName = strrchr(procname, '\\');
    377     std::stringstream outDir;
    378     outDir << JITTER_OUTPUT_DIR << pBaseName << "_" << pid;
    379     CreateDirectoryPath(outDir.str().c_str());
    380     return outDir.str();
    381 #endif
    382     return "";
    383 }
    384 
    385 //////////////////////////////////////////////////////////////////////////
    386 /// @brief Dump function to file.
    387 void JitManager::DumpToFile(Module *M, const char *fileName)
    388 {
    389     if (KNOB_DUMP_SHADER_IR)
    390     {
    391         std::string outDir = GetOutputDir();
    392 
    393         std::error_code EC;
    394         const char *funcName = M->getName().data();
    395         char fName[256];
    396 #if defined(_WIN32)
    397         sprintf(fName, "%s\\%s.%s.ll", outDir.c_str(), funcName, fileName);
    398 #else
    399         sprintf(fName, "%s.%s.ll", funcName, fileName);
    400 #endif
    401         raw_fd_ostream fd(fName, EC, llvm::sys::fs::F_None);
    402         M->print(fd, nullptr);
    403         fd.flush();
    404     }
    405 }
    406 
    407 //////////////////////////////////////////////////////////////////////////
    408 /// @brief Dump function to file.
    409 void JitManager::DumpToFile(Function *f, const char *fileName)
    410 {
    411     if (KNOB_DUMP_SHADER_IR)
    412     {
    413         std::string outDir = GetOutputDir();
    414 
    415         std::error_code EC;
    416         const char *funcName = f->getName().data();
    417         char fName[256];
    418 #if defined(_WIN32)
    419         sprintf(fName, "%s\\%s.%s.ll", outDir.c_str(), funcName, fileName);
    420 #else
    421         sprintf(fName, "%s.%s.ll", funcName, fileName);
    422 #endif
    423         raw_fd_ostream fd(fName, EC, llvm::sys::fs::F_None);
    424         Module* pModule = f->getParent();
    425         pModule->print(fd, nullptr);
    426 
    427 #if defined(_WIN32)
    428         sprintf(fName, "%s\\cfg.%s.%s.dot", outDir.c_str(), funcName, fileName);
    429 #else
    430         sprintf(fName, "cfg.%s.%s.dot", funcName, fileName);
    431 #endif
    432         fd.flush();
    433 
    434         raw_fd_ostream fd_cfg(fName, EC, llvm::sys::fs::F_Text);
    435         WriteGraph(fd_cfg, (const Function*)f);
    436 
    437         fd_cfg.flush();
    438     }
    439 }
    440 
    441 extern "C"
    442 {
    443     bool g_DllActive = true;
    444 
    445     //////////////////////////////////////////////////////////////////////////
    446     /// @brief Create JIT context.
    447     /// @param simdWidth - SIMD width to be used in generated program.
    448     HANDLE JITCALL JitCreateContext(uint32_t targetSimdWidth, const char* arch, const char* core)
    449     {
    450         return new JitManager(targetSimdWidth, arch, core);
    451     }
    452 
    453     //////////////////////////////////////////////////////////////////////////
    454     /// @brief Destroy JIT context.
    455     void JITCALL JitDestroyContext(HANDLE hJitContext)
    456     {
    457         if (g_DllActive)
    458         {
    459             delete reinterpret_cast<JitManager*>(hJitContext);
    460         }
    461     }
    462 }
    463 
    464 //////////////////////////////////////////////////////////////////////////
    465 /// JitCache
    466 //////////////////////////////////////////////////////////////////////////
    467 
    468 //////////////////////////////////////////////////////////////////////////
    469 /// JitCacheFileHeader
    470 //////////////////////////////////////////////////////////////////////////
    471 struct JitCacheFileHeader
    472 {
    473     void Init(
    474         uint32_t llCRC,
    475         uint32_t objCRC,
    476         const std::string& moduleID,
    477         const std::string& cpu,
    478         uint32_t optLevel,
    479         uint64_t objSize)
    480     {
    481         m_objSize = objSize;
    482         m_llCRC = llCRC;
    483         m_objCRC = objCRC;
    484         strncpy(m_ModuleID, moduleID.c_str(), JC_STR_MAX_LEN - 1);
    485         m_ModuleID[JC_STR_MAX_LEN - 1] = 0;
    486         strncpy(m_Cpu, cpu.c_str(), JC_STR_MAX_LEN - 1);
    487         m_Cpu[JC_STR_MAX_LEN - 1] = 0;
    488         m_optLevel = optLevel;
    489     }
    490 
    491 #if defined(ENABLE_JIT_DEBUG)
    492     void Init(
    493         uint32_t llCRC,
    494         uint32_t objCRC,
    495         const std::string& moduleID,
    496         const std::string& cpu,
    497         uint32_t optLevel,
    498         uint64_t objSize,
    499         uint32_t modCRC,
    500         uint64_t modSize)
    501     {
    502         Init(llCRC, objCRC, moduleID, cpu, optLevel, objSize);
    503         m_modCRC = modCRC;
    504         m_modSize = modSize;
    505     }
    506 
    507     void Init(
    508         uint32_t modCRC,
    509         uint64_t modSize)
    510     {
    511         m_modCRC = modCRC;
    512         m_modSize = modSize;
    513     }
    514 #endif
    515 
    516     bool IsValid(uint32_t llCRC, const std::string& moduleID, const std::string& cpu, uint32_t optLevel)
    517     {
    518         if ((m_MagicNumber != JC_MAGIC_NUMBER) ||
    519             (m_llCRC != llCRC) ||
    520             (m_platformKey != JC_PLATFORM_KEY) ||
    521             (m_optLevel != optLevel))
    522         {
    523             return false;
    524         }
    525 
    526         m_ModuleID[JC_STR_MAX_LEN - 1] = 0;
    527         if (strncmp(moduleID.c_str(), m_ModuleID, JC_STR_MAX_LEN - 1))
    528         {
    529             return false;
    530         }
    531 
    532         m_Cpu[JC_STR_MAX_LEN - 1] = 0;
    533         if (strncmp(cpu.c_str(), m_Cpu, JC_STR_MAX_LEN - 1))
    534         {
    535             return false;
    536         }
    537 
    538         return true;
    539     }
    540 
    541     uint64_t GetObjectSize() const { return m_objSize; }
    542     uint64_t GetObjectCRC() const { return m_objCRC; }
    543 #if defined(ENABLE_JIT_DEBUG)
    544     uint64_t GetSharedModuleSize() const { return m_modSize; }
    545     uint64_t GetSharedModuleCRC() const { return m_modCRC; }
    546 #endif
    547 
    548 private:
    549     static const uint64_t   JC_MAGIC_NUMBER = 0xfedcba9876543211ULL + 3;
    550     static const size_t     JC_STR_MAX_LEN = 32;
    551     static const uint32_t   JC_PLATFORM_KEY =
    552         (LLVM_VERSION_MAJOR << 24)  |
    553         (LLVM_VERSION_MINOR << 16)  |
    554         (LLVM_VERSION_PATCH << 8)   |
    555         ((sizeof(void*) > sizeof(uint32_t)) ? 1 : 0);
    556 
    557     uint64_t m_MagicNumber = JC_MAGIC_NUMBER;
    558     uint64_t m_objSize = 0;
    559     uint32_t m_llCRC = 0;
    560     uint32_t m_platformKey = JC_PLATFORM_KEY;
    561     uint32_t m_objCRC = 0;
    562     uint32_t m_optLevel = 0;
    563     char m_ModuleID[JC_STR_MAX_LEN] = {};
    564     char m_Cpu[JC_STR_MAX_LEN] = {};
    565 #if defined(ENABLE_JIT_DEBUG)
    566     uint32_t m_modCRC = 0;
    567     uint64_t m_modSize = 0;
    568 #endif
    569 };
    570 
    571 static inline uint32_t ComputeModuleCRC(const llvm::Module* M)
    572 {
    573     std::string bitcodeBuffer;
    574     raw_string_ostream bitcodeStream(bitcodeBuffer);
    575 
    576     llvm::WriteBitcodeToFile(M, bitcodeStream);
    577     //M->print(bitcodeStream, nullptr, false);
    578 
    579     bitcodeStream.flush();
    580 
    581     return ComputeCRC(0, bitcodeBuffer.data(), bitcodeBuffer.size());
    582 }
    583 
    584 /// constructor
    585 JitCache::JitCache()
    586 {
    587 #if defined(__APPLE__) || defined(FORCE_LINUX) || defined(__linux__) || defined(__gnu_linux__)
    588     if (strncmp(KNOB_JIT_CACHE_DIR.c_str(), "~/", 2) == 0) {
    589         char *homedir;
    590         if (!(homedir = getenv("HOME"))) {
    591             homedir = getpwuid(getuid())->pw_dir;
    592         }
    593         mCacheDir = homedir;
    594         mCacheDir += (KNOB_JIT_CACHE_DIR.c_str() + 1);
    595     } else
    596 #endif
    597     {
    598         mCacheDir = KNOB_JIT_CACHE_DIR;
    599     }
    600 }
    601 
    602 #if defined(_WIN32)
    603 int ExecUnhookedProcess(const char* pCmdLine)
    604 {
    605     static const char *g_pEnv = "RASTY_DISABLE_HOOK=1\0";
    606 
    607     STARTUPINFOA StartupInfo{};
    608     StartupInfo.cb = sizeof(STARTUPINFOA);
    609     PROCESS_INFORMATION procInfo{};
    610 
    611     BOOL ProcessValue = CreateProcessA(
    612         NULL,
    613         (LPSTR)pCmdLine,
    614         NULL,
    615         NULL,
    616         TRUE,
    617         0,
    618         (LPVOID)g_pEnv,
    619         NULL,
    620         &StartupInfo,
    621         &procInfo);
    622 
    623     if (ProcessValue && procInfo.hProcess)
    624     {
    625         WaitForSingleObject(procInfo.hProcess, INFINITE);
    626         DWORD exitVal = 0;
    627         if (!GetExitCodeProcess(procInfo.hProcess, &exitVal))
    628         {
    629             exitVal = 1;
    630         }
    631 
    632         CloseHandle(procInfo.hProcess);
    633 
    634         return exitVal;
    635     }
    636 
    637     return -1;
    638 }
    639 #endif
    640 
    641 #if defined(_WIN64) && defined(ENABLE_JIT_DEBUG) && defined(JIT_BASE_DIR)
    642 EXTERN_C IMAGE_DOS_HEADER __ImageBase;
    643 static __inline HINSTANCE GetModuleHINSTANCE() { return (HINSTANCE)&__ImageBase; }
    644 #endif
    645 
    646 /// notifyObjectCompiled - Provides a pointer to compiled code for Module M.
    647 void JitCache::notifyObjectCompiled(const llvm::Module *M, llvm::MemoryBufferRef Obj)
    648 {
    649     const std::string& moduleID = M->getModuleIdentifier();
    650     if (!moduleID.length())
    651     {
    652         return;
    653     }
    654 
    655     if (!llvm::sys::fs::exists(mCacheDir.str()) &&
    656         llvm::sys::fs::create_directories(mCacheDir.str()))
    657     {
    658         SWR_INVALID("Unable to create directory: %s", mCacheDir.c_str());
    659         return;
    660     }
    661 
    662     JitCacheFileHeader header;
    663 
    664     llvm::SmallString<MAX_PATH> filePath = mCacheDir;
    665     llvm::sys::path::append(filePath, moduleID);
    666 
    667     llvm::SmallString<MAX_PATH> objPath = filePath;
    668     objPath += JIT_OBJ_EXT;
    669 
    670     {
    671         std::error_code err;
    672         llvm::raw_fd_ostream fileObj(objPath.c_str(), err, llvm::sys::fs::F_None);
    673         fileObj << Obj.getBuffer();
    674         fileObj.flush();
    675     }
    676 
    677 
    678     {
    679         std::error_code err;
    680         llvm::raw_fd_ostream fileObj(filePath.c_str(), err, llvm::sys::fs::F_None);
    681 
    682         uint32_t objcrc = ComputeCRC(0, Obj.getBufferStart(), Obj.getBufferSize());
    683 
    684         header.Init(mCurrentModuleCRC, objcrc, moduleID, mCpu, mOptLevel, Obj.getBufferSize());
    685 
    686         fileObj.write((const char*)&header, sizeof(header));
    687         fileObj.flush();
    688     }
    689 }
    690 
    691 /// Returns a pointer to a newly allocated MemoryBuffer that contains the
    692 /// object which corresponds with Module M, or 0 if an object is not
    693 /// available.
    694 std::unique_ptr<llvm::MemoryBuffer> JitCache::getObject(const llvm::Module* M)
    695 {
    696     const std::string& moduleID = M->getModuleIdentifier();
    697     mCurrentModuleCRC = ComputeModuleCRC(M);
    698 
    699     if (!moduleID.length())
    700     {
    701         return nullptr;
    702     }
    703 
    704     if (!llvm::sys::fs::exists(mCacheDir))
    705     {
    706         return nullptr;
    707     }
    708 
    709     llvm::SmallString<MAX_PATH> filePath = mCacheDir;
    710     llvm::sys::path::append(filePath, moduleID);
    711 
    712     llvm::SmallString<MAX_PATH> objFilePath = filePath;
    713     objFilePath += JIT_OBJ_EXT;
    714 
    715 #if defined(ENABLE_JIT_DEBUG)
    716     FILE* fpModuleIn = nullptr;
    717 #endif
    718     FILE* fpObjIn = nullptr;
    719     FILE* fpIn = fopen(filePath.c_str(), "rb");
    720     if (!fpIn)
    721     {
    722         return nullptr;
    723     }
    724 
    725     std::unique_ptr<llvm::MemoryBuffer> pBuf = nullptr;
    726     do
    727     {
    728         JitCacheFileHeader header;
    729         if (!fread(&header, sizeof(header), 1, fpIn))
    730         {
    731             break;
    732         }
    733 
    734         if (!header.IsValid(mCurrentModuleCRC, moduleID, mCpu, mOptLevel))
    735         {
    736             break;
    737         }
    738 
    739         fpObjIn = fopen(objFilePath.c_str(), "rb");
    740         if (!fpObjIn)
    741         {
    742             break;
    743         }
    744 
    745 #if LLVM_VERSION_MAJOR < 6
    746         pBuf = llvm::MemoryBuffer::getNewUninitMemBuffer(size_t(header.GetObjectSize()));
    747 #else
    748         pBuf = llvm::WritableMemoryBuffer::getNewUninitMemBuffer(size_t(header.GetObjectSize()));
    749 #endif
    750         if (!fread(const_cast<char*>(pBuf->getBufferStart()), header.GetObjectSize(), 1, fpObjIn))
    751         {
    752             pBuf = nullptr;
    753             break;
    754         }
    755 
    756         if (header.GetObjectCRC() != ComputeCRC(0, pBuf->getBufferStart(), pBuf->getBufferSize()))
    757         {
    758             SWR_TRACE("Invalid object cache file, ignoring: %s", filePath.c_str());
    759             pBuf = nullptr;
    760             break;
    761         }
    762 
    763     }
    764     while (0);
    765 
    766     fclose(fpIn);
    767 
    768     if (fpObjIn)
    769     {
    770         fclose(fpObjIn);
    771     }
    772 
    773 #if defined(ENABLE_JIT_DEBUG)
    774     if (fpModuleIn)
    775     {
    776         fclose(fpModuleIn);
    777     }
    778 #endif
    779 
    780     return pBuf;
    781 }
    782