• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
JitManager(uint32_t simdWidth,const char * arch,const char * core)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.
SetupNewModule()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 
CreateDebugStructType(StructType * pType,const std::string & name,DIFile * pFile,uint32_t lineNum,const std::vector<std::pair<std::string,uint32_t>> & members)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 
GetDebugArrayType(Type * pTy)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
GetDebugType(Type * pTy)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
GetDebugFunctionType(Type * pTy)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 
GetDebugIntegerType(Type * pTy)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 
GetDebugVectorType(Type * pTy)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.
DumpAsm(Function * pFunction,const char * fileName)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 
GetOutputDir()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.
DumpToFile(Module * M,const char * fileName)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.
DumpToFile(Function * f,const char * fileName)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.
JitCreateContext(uint32_t targetSimdWidth,const char * arch,const char * core)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.
JitDestroyContext(HANDLE hJitContext)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 {
InitJitCacheFileHeader473     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)
InitJitCacheFileHeader492     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 
InitJitCacheFileHeader507     void Init(
508         uint32_t modCRC,
509         uint64_t modSize)
510     {
511         m_modCRC = modCRC;
512         m_modSize = modSize;
513     }
514 #endif
515 
IsValidJitCacheFileHeader516     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 
GetObjectSizeJitCacheFileHeader541     uint64_t GetObjectSize() const { return m_objSize; }
GetObjectCRCJitCacheFileHeader542     uint64_t GetObjectCRC() const { return m_objCRC; }
543 #if defined(ENABLE_JIT_DEBUG)
GetSharedModuleSizeJitCacheFileHeader544     uint64_t GetSharedModuleSize() const { return m_modSize; }
GetSharedModuleCRCJitCacheFileHeader545     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 
ComputeModuleCRC(const llvm::Module * M)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
JitCache()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)
ExecUnhookedProcess(const char * pCmdLine)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;
GetModuleHINSTANCE()643 static __inline HINSTANCE GetModuleHINSTANCE() { return (HINSTANCE)&__ImageBase; }
644 #endif
645 
646 /// notifyObjectCompiled - Provides a pointer to compiled code for Module M.
notifyObjectCompiled(const llvm::Module * M,llvm::MemoryBufferRef Obj)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.
getObject(const llvm::Module * M)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