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