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