1/**************************************************************************** 2 * Copyright (C) 2014-2018 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 56using namespace llvm; 57using namespace SwrJit; 58 59////////////////////////////////////////////////////////////////////////// 60/// @brief Contructor for JitManager. 61/// @param simdWidth - SIMD width to be used in generated program. 62JitManager::JitManager(uint32_t simdWidth, const char* arch, const char* core) : 63 mContext(), mBuilder(mContext), mIsModuleFinalized(true), mJitNumber(0), mVWidth(simdWidth), 64 mArch(arch) 65{ 66 mpCurrentModule = nullptr; 67 mpExec = nullptr; 68 69 InitializeNativeTarget(); 70 InitializeNativeTargetAsmPrinter(); 71 InitializeNativeTargetDisassembler(); 72 73 74 // force JIT to use the same CPU arch as the rest of swr 75 if (mArch.AVX512F()) 76 { 77#if USE_SIMD16_SHADERS 78 if (mArch.AVX512ER()) 79 { 80 mHostCpuName = StringRef("knl"); 81 } 82 else 83 { 84 mHostCpuName = StringRef("skylake-avx512"); 85 } 86 mUsingAVX512 = true; 87#else 88 mHostCpuName = StringRef("core-avx2"); 89#endif 90 if (mVWidth == 0) 91 { 92 mVWidth = 8; 93 } 94 } 95 else if (mArch.AVX2()) 96 { 97 mHostCpuName = StringRef("core-avx2"); 98 if (mVWidth == 0) 99 { 100 mVWidth = 8; 101 } 102 } 103 else if (mArch.AVX()) 104 { 105 if (mArch.F16C()) 106 { 107 mHostCpuName = StringRef("core-avx-i"); 108 } 109 else 110 { 111 mHostCpuName = StringRef("corei7-avx"); 112 } 113 if (mVWidth == 0) 114 { 115 mVWidth = 8; 116 } 117 } 118 else 119 { 120 SWR_INVALID("Jitting requires at least AVX ISA support"); 121 } 122 123 124 mOptLevel = CodeGenOpt::Aggressive; 125 126 if (KNOB_JIT_OPTIMIZATION_LEVEL >= CodeGenOpt::None && 127 KNOB_JIT_OPTIMIZATION_LEVEL <= CodeGenOpt::Aggressive) 128 { 129 mOptLevel = CodeGenOpt::Level(KNOB_JIT_OPTIMIZATION_LEVEL); 130 } 131 132 if (KNOB_JIT_ENABLE_CACHE) 133 { 134 mCache.Init(this, mHostCpuName, mOptLevel); 135 } 136 137 SetupNewModule(); 138 mIsModuleFinalized = true; 139 140 // fetch function signature 141#if USE_SIMD16_SHADERS 142 // typedef void(__cdecl *PFN_FETCH_FUNC)(SWR_FETCH_CONTEXT& fetchInfo, simd16vertex& out); 143#else 144 // typedef void(__cdecl *PFN_FETCH_FUNC)(SWR_FETCH_CONTEXT& fetchInfo, simdvertex& out); 145#endif 146 std::vector<Type*> fsArgs; 147 148 // llvm5 is picky and does not take a void * type 149 fsArgs.push_back(PointerType::get(Gen_SWR_FETCH_CONTEXT(this), 0)); 150 151 fsArgs.push_back(Type::getInt8PtrTy(mContext)); 152 153 fsArgs.push_back(PointerType::get(Gen_SWR_FETCH_CONTEXT(this), 0)); 154#if USE_SIMD16_SHADERS 155 fsArgs.push_back(PointerType::get(Gen_simd16vertex(this), 0)); 156#else 157 fsArgs.push_back(PointerType::get(Gen_simdvertex(this), 0)); 158#endif 159 160 mFetchShaderTy = FunctionType::get(Type::getVoidTy(mContext), fsArgs, false); 161 162#if defined(_WIN32) 163 // explicitly instantiate used symbols from potentially staticly linked libs 164 sys::DynamicLibrary::AddSymbol("exp2f", &exp2f); 165 sys::DynamicLibrary::AddSymbol("log2f", &log2f); 166 sys::DynamicLibrary::AddSymbol("sinf", &sinf); 167 sys::DynamicLibrary::AddSymbol("cosf", &cosf); 168 sys::DynamicLibrary::AddSymbol("powf", &powf); 169#endif 170 171#if defined(_WIN32) 172 if (KNOB_DUMP_SHADER_IR) 173 { 174 CreateDirectoryPath(INTEL_OUTPUT_DIR); 175 CreateDirectoryPath(SWR_OUTPUT_DIR); 176 CreateDirectoryPath(JITTER_OUTPUT_DIR); 177 } 178#endif 179} 180 181void JitManager::CreateExecEngine(std::unique_ptr<Module> pModule) 182{ 183 TargetOptions tOpts; 184 tOpts.AllowFPOpFusion = FPOpFusion::Fast; 185 tOpts.NoInfsFPMath = false; 186 tOpts.NoNaNsFPMath = false; 187 tOpts.UnsafeFPMath = false; 188 189 // tOpts.PrintMachineCode = true; 190 191 mpExec = EngineBuilder(std::move(pModule)) 192 .setTargetOptions(tOpts) 193 .setOptLevel(mOptLevel) 194 .setMCPU(mHostCpuName) 195 .create(); 196 197 if (KNOB_JIT_ENABLE_CACHE) 198 { 199 mpExec->setObjectCache(&mCache); 200 } 201 202#if LLVM_USE_INTEL_JITEVENTS 203 JITEventListener* vTune = JITEventListener::createIntelJITEventListener(); 204 mpExec->RegisterJITEventListener(vTune); 205#endif 206 207 mvExecEngines.push_back(mpExec); 208} 209 210////////////////////////////////////////////////////////////////////////// 211/// @brief Create new LLVM module. 212void JitManager::SetupNewModule() 213{ 214 SWR_ASSERT(mIsModuleFinalized == true && "Current module is not finalized!"); 215 216 std::unique_ptr<Module> newModule(new Module("", mContext)); 217 mpCurrentModule = newModule.get(); 218 mpCurrentModule->setTargetTriple(sys::getProcessTriple()); 219 CreateExecEngine(std::move(newModule)); 220 mIsModuleFinalized = false; 221} 222 223 224DIType* 225JitManager::CreateDebugStructType(StructType* pType, 226 const std::string& name, 227 DIFile* pFile, 228 uint32_t lineNum, 229 const std::vector<std::pair<std::string, uint32_t>>& members) 230{ 231 DIBuilder builder(*mpCurrentModule); 232 SmallVector<Metadata*, 8> ElemTypes; 233 DataLayout DL = DataLayout(mpCurrentModule); 234 uint32_t size = DL.getTypeAllocSizeInBits(pType); 235 uint32_t alignment = DL.getABITypeAlignment(pType); 236 DINode::DIFlags flags = DINode::DIFlags::FlagPublic; 237 238 DICompositeType* pDIStructTy = builder.createStructType(pFile, 239 name, 240 pFile, 241 lineNum, 242 size, 243 alignment, 244 flags, 245 nullptr, 246 builder.getOrCreateArray(ElemTypes)); 247 248 // Register mapping now to break loops (in case struct contains itself or pointers to itself) 249 mDebugStructMap[pType] = pDIStructTy; 250 251 uint32_t idx = 0; 252 for (auto& elem : pType->elements()) 253 { 254 std::string name = members[idx].first; 255 uint32_t lineNum = members[idx].second; 256 size = DL.getTypeAllocSizeInBits(elem); 257 alignment = DL.getABITypeAlignment(elem); 258 uint32_t offset = DL.getStructLayout(pType)->getElementOffsetInBits(idx); 259 llvm::DIType* pDebugTy = GetDebugType(elem); 260 ElemTypes.push_back(builder.createMemberType( 261 pDIStructTy, name, pFile, lineNum, size, alignment, offset, flags, pDebugTy)); 262 263 idx++; 264 } 265 266 pDIStructTy->replaceElements(builder.getOrCreateArray(ElemTypes)); 267 return pDIStructTy; 268} 269 270DIType* JitManager::GetDebugArrayType(Type* pTy) 271{ 272 DIBuilder builder(*mpCurrentModule); 273 DataLayout DL = DataLayout(mpCurrentModule); 274 ArrayType* pArrayTy = cast<ArrayType>(pTy); 275 uint32_t size = DL.getTypeAllocSizeInBits(pArrayTy); 276 uint32_t alignment = DL.getABITypeAlignment(pArrayTy); 277 278 SmallVector<Metadata*, 8> Elems; 279 Elems.push_back(builder.getOrCreateSubrange(0, pArrayTy->getNumElements())); 280 return builder.createArrayType( 281 size, alignment, GetDebugType(pArrayTy->getElementType()), builder.getOrCreateArray(Elems)); 282} 283 284// Create a DIType from llvm Type 285DIType* JitManager::GetDebugType(Type* pTy) 286{ 287 DIBuilder builder(*mpCurrentModule); 288 Type::TypeID id = pTy->getTypeID(); 289 290 switch (id) 291 { 292 case Type::VoidTyID: 293 return builder.createUnspecifiedType("void"); 294 break; 295 case Type::HalfTyID: 296 return builder.createBasicType("float16", 16, dwarf::DW_ATE_float); 297 break; 298 case Type::FloatTyID: 299 return builder.createBasicType("float", 32, dwarf::DW_ATE_float); 300 break; 301 case Type::DoubleTyID: 302 return builder.createBasicType("double", 64, dwarf::DW_ATE_float); 303 break; 304 case Type::IntegerTyID: 305 return GetDebugIntegerType(pTy); 306 break; 307 case Type::StructTyID: 308 return GetDebugStructType(pTy); 309 break; 310 case Type::ArrayTyID: 311 return GetDebugArrayType(pTy); 312 break; 313 case Type::PointerTyID: 314 return builder.createPointerType(GetDebugType(pTy->getPointerElementType()), 64, 64); 315 break; 316 case Type::VectorTyID: 317 return GetDebugVectorType(pTy); 318 break; 319 case Type::FunctionTyID: 320 return GetDebugFunctionType(pTy); 321 break; 322 default: 323 SWR_ASSERT(false, "Unimplemented llvm type"); 324 } 325 return nullptr; 326} 327 328// Create a DISubroutineType from an llvm FunctionType 329DIType* JitManager::GetDebugFunctionType(Type* pTy) 330{ 331 SmallVector<Metadata*, 8> ElemTypes; 332 FunctionType* pFuncTy = cast<FunctionType>(pTy); 333 DIBuilder builder(*mpCurrentModule); 334 335 // Add result type 336 ElemTypes.push_back(GetDebugType(pFuncTy->getReturnType())); 337 338 // Add arguments 339 for (auto& param : pFuncTy->params()) 340 { 341 ElemTypes.push_back(GetDebugType(param)); 342 } 343 344 return builder.createSubroutineType(builder.getOrCreateTypeArray(ElemTypes)); 345} 346 347DIType* JitManager::GetDebugIntegerType(Type* pTy) 348{ 349 DIBuilder builder(*mpCurrentModule); 350 IntegerType* pIntTy = cast<IntegerType>(pTy); 351 switch (pIntTy->getBitWidth()) 352 { 353 case 1: 354 return builder.createBasicType("int1", 1, dwarf::DW_ATE_unsigned); 355 break; 356 case 8: 357 return builder.createBasicType("int8", 8, dwarf::DW_ATE_signed); 358 break; 359 case 16: 360 return builder.createBasicType("int16", 16, dwarf::DW_ATE_signed); 361 break; 362 case 32: 363 return builder.createBasicType("int", 32, dwarf::DW_ATE_signed); 364 break; 365 case 64: 366 return builder.createBasicType("int64", 64, dwarf::DW_ATE_signed); 367 break; 368 case 128: 369 return builder.createBasicType("int128", 128, dwarf::DW_ATE_signed); 370 break; 371 default: 372 SWR_ASSERT(false, "Unimplemented integer bit width"); 373 } 374 return nullptr; 375} 376 377DIType* JitManager::GetDebugVectorType(Type* pTy) 378{ 379 DIBuilder builder(*mpCurrentModule); 380 VectorType* pVecTy = cast<VectorType>(pTy); 381 DataLayout DL = DataLayout(mpCurrentModule); 382 uint32_t size = DL.getTypeAllocSizeInBits(pVecTy); 383 uint32_t alignment = DL.getABITypeAlignment(pVecTy); 384 SmallVector<Metadata*, 1> Elems; 385 Elems.push_back(builder.getOrCreateSubrange(0, pVecTy->getVectorNumElements())); 386 387 return builder.createVectorType(size, 388 alignment, 389 GetDebugType(pVecTy->getVectorElementType()), 390 builder.getOrCreateArray(Elems)); 391} 392 393////////////////////////////////////////////////////////////////////////// 394/// @brief Dump function x86 assembly to file. 395/// @note This should only be called after the module has been jitted to x86 and the 396/// module will not be further accessed. 397void JitManager::DumpAsm(Function* pFunction, const char* fileName) 398{ 399 if (KNOB_DUMP_SHADER_IR) 400 { 401#if defined(_WIN32) 402 DWORD pid = GetCurrentProcessId(); 403 char procname[MAX_PATH]; 404 GetModuleFileNameA(NULL, procname, MAX_PATH); 405 const char* pBaseName = strrchr(procname, '\\'); 406 std::stringstream outDir; 407 outDir << JITTER_OUTPUT_DIR << pBaseName << "_" << pid << std::ends; 408 CreateDirectoryPath(outDir.str().c_str()); 409#endif 410 411 std::error_code EC; 412 Module* pModule = pFunction->getParent(); 413 const char* funcName = pFunction->getName().data(); 414 char fName[256]; 415#if defined(_WIN32) 416 sprintf(fName, "%s\\%s.%s.asm", outDir.str().c_str(), funcName, fileName); 417#else 418 sprintf(fName, "%s.%s.asm", funcName, fileName); 419#endif 420 421 raw_fd_ostream filestream(fName, EC, llvm::sys::fs::F_None); 422 423 legacy::PassManager* pMPasses = new legacy::PassManager(); 424 auto* pTarget = mpExec->getTargetMachine(); 425 pTarget->Options.MCOptions.AsmVerbose = true; 426#if LLVM_VERSION_MAJOR >= 7 427 pTarget->addPassesToEmitFile( 428 *pMPasses, filestream, nullptr, TargetMachine::CGFT_AssemblyFile); 429#else 430 pTarget->addPassesToEmitFile(*pMPasses, filestream, TargetMachine::CGFT_AssemblyFile); 431#endif 432 pMPasses->run(*pModule); 433 delete pMPasses; 434 pTarget->Options.MCOptions.AsmVerbose = false; 435 } 436} 437 438std::string JitManager::GetOutputDir() 439{ 440#if defined(_WIN32) 441 DWORD pid = GetCurrentProcessId(); 442 char procname[MAX_PATH]; 443 GetModuleFileNameA(NULL, procname, MAX_PATH); 444 const char* pBaseName = strrchr(procname, '\\'); 445 std::stringstream outDir; 446 outDir << JITTER_OUTPUT_DIR << pBaseName << "_" << pid; 447 CreateDirectoryPath(outDir.str().c_str()); 448 return outDir.str(); 449#endif 450 return ""; 451} 452 453////////////////////////////////////////////////////////////////////////// 454/// @brief Dump function to file. 455void JitManager::DumpToFile(Module* M, const char* fileName, llvm::AssemblyAnnotationWriter* annotater) 456{ 457 if (KNOB_DUMP_SHADER_IR) 458 { 459 std::string outDir = GetOutputDir(); 460 461 std::error_code EC; 462 const char* funcName = M->getName().data(); 463 char fName[256]; 464#if defined(_WIN32) 465 sprintf(fName, "%s\\%s.%s.ll", outDir.c_str(), funcName, fileName); 466#else 467 sprintf(fName, "%s.%s.ll", funcName, fileName); 468#endif 469 raw_fd_ostream fd(fName, EC, llvm::sys::fs::F_None); 470 M->print(fd, annotater); 471 fd.flush(); 472 } 473} 474 475////////////////////////////////////////////////////////////////////////// 476/// @brief Dump function to file. 477void JitManager::DumpToFile(Function* f, const char* fileName) 478{ 479 if (KNOB_DUMP_SHADER_IR) 480 { 481 std::string outDir = GetOutputDir(); 482 483 std::error_code EC; 484 const char* funcName = f->getName().data(); 485 char fName[256]; 486#if defined(_WIN32) 487 sprintf(fName, "%s\\%s.%s.ll", outDir.c_str(), funcName, fileName); 488#else 489 sprintf(fName, "%s.%s.ll", funcName, fileName); 490#endif 491 raw_fd_ostream fd(fName, EC, llvm::sys::fs::F_None); 492 f->print(fd, nullptr); 493 494#if defined(_WIN32) 495 sprintf(fName, "%s\\cfg.%s.%s.dot", outDir.c_str(), funcName, fileName); 496#else 497 sprintf(fName, "cfg.%s.%s.dot", funcName, fileName); 498#endif 499 fd.flush(); 500 501 raw_fd_ostream fd_cfg(fName, EC, llvm::sys::fs::F_Text); 502 WriteGraph(fd_cfg, (const Function*)f); 503 504 fd_cfg.flush(); 505 } 506} 507 508extern "C" { 509bool g_DllActive = true; 510 511////////////////////////////////////////////////////////////////////////// 512/// @brief Create JIT context. 513/// @param simdWidth - SIMD width to be used in generated program. 514HANDLE JITCALL JitCreateContext(uint32_t targetSimdWidth, const char* arch, const char* core) 515{ 516 return new JitManager(targetSimdWidth, arch, core); 517} 518 519////////////////////////////////////////////////////////////////////////// 520/// @brief Destroy JIT context. 521void JITCALL JitDestroyContext(HANDLE hJitContext) 522{ 523 if (g_DllActive) 524 { 525 delete reinterpret_cast<JitManager*>(hJitContext); 526 } 527} 528} 529 530////////////////////////////////////////////////////////////////////////// 531/// JitCache 532////////////////////////////////////////////////////////////////////////// 533 534////////////////////////////////////////////////////////////////////////// 535/// JitCacheFileHeader 536////////////////////////////////////////////////////////////////////////// 537struct JitCacheFileHeader 538{ 539 void Init(uint32_t llCRC, 540 uint32_t objCRC, 541 const std::string& moduleID, 542 const std::string& cpu, 543 uint32_t optLevel, 544 uint64_t objSize) 545 { 546 m_objSize = objSize; 547 m_llCRC = llCRC; 548 m_objCRC = objCRC; 549 strncpy(m_ModuleID, moduleID.c_str(), JC_STR_MAX_LEN - 1); 550 m_ModuleID[JC_STR_MAX_LEN - 1] = 0; 551 strncpy(m_Cpu, cpu.c_str(), JC_STR_MAX_LEN - 1); 552 m_Cpu[JC_STR_MAX_LEN - 1] = 0; 553 m_optLevel = optLevel; 554 } 555 556 557 bool 558 IsValid(uint32_t llCRC, const std::string& moduleID, const std::string& cpu, uint32_t optLevel) 559 { 560 if ((m_MagicNumber != JC_MAGIC_NUMBER) || (m_llCRC != llCRC) || 561 (m_platformKey != JC_PLATFORM_KEY) || (m_optLevel != optLevel)) 562 { 563 return false; 564 } 565 566 m_ModuleID[JC_STR_MAX_LEN - 1] = 0; 567 if (strncmp(moduleID.c_str(), m_ModuleID, JC_STR_MAX_LEN - 1)) 568 { 569 return false; 570 } 571 572 m_Cpu[JC_STR_MAX_LEN - 1] = 0; 573 if (strncmp(cpu.c_str(), m_Cpu, JC_STR_MAX_LEN - 1)) 574 { 575 return false; 576 } 577 578 return true; 579 } 580 581 uint64_t GetObjectSize() const { return m_objSize; } 582 uint64_t GetObjectCRC() const { return m_objCRC; } 583 584private: 585 static const uint64_t JC_MAGIC_NUMBER = 0xfedcba9876543210ULL + 6; 586 static const size_t JC_STR_MAX_LEN = 32; 587 static const uint32_t JC_PLATFORM_KEY = (LLVM_VERSION_MAJOR << 24) | 588 (LLVM_VERSION_MINOR << 16) | (LLVM_VERSION_PATCH << 8) | 589 ((sizeof(void*) > sizeof(uint32_t)) ? 1 : 0); 590 591 uint64_t m_MagicNumber = JC_MAGIC_NUMBER; 592 uint64_t m_objSize = 0; 593 uint32_t m_llCRC = 0; 594 uint32_t m_platformKey = JC_PLATFORM_KEY; 595 uint32_t m_objCRC = 0; 596 uint32_t m_optLevel = 0; 597 char m_ModuleID[JC_STR_MAX_LEN] = {}; 598 char m_Cpu[JC_STR_MAX_LEN] = {}; 599}; 600 601static inline uint32_t ComputeModuleCRC(const llvm::Module* M) 602{ 603 std::string bitcodeBuffer; 604 raw_string_ostream bitcodeStream(bitcodeBuffer); 605 606#if LLVM_VERSION_MAJOR >= 7 607 llvm::WriteBitcodeToFile(*M, bitcodeStream); 608#else 609 llvm::WriteBitcodeToFile(M, bitcodeStream); 610#endif 611 // M->print(bitcodeStream, nullptr, false); 612 613 bitcodeStream.flush(); 614 615 return ComputeCRC(0, bitcodeBuffer.data(), bitcodeBuffer.size()); 616} 617 618/// constructor 619JitCache::JitCache() 620{ 621#if defined(__APPLE__) || defined(FORCE_LINUX) || defined(__linux__) || defined(__gnu_linux__) 622 if (strncmp(KNOB_JIT_CACHE_DIR.c_str(), "~/", 2) == 0) 623 { 624 char* homedir; 625 if (!(homedir = getenv("HOME"))) 626 { 627 homedir = getpwuid(getuid())->pw_dir; 628 } 629 mCacheDir = homedir; 630 mCacheDir += (KNOB_JIT_CACHE_DIR.c_str() + 1); 631 } 632 else 633#endif 634 { 635 mCacheDir = KNOB_JIT_CACHE_DIR; 636 } 637 638 // Create cache dir at startup to allow jitter to write debug.ll files 639 // to that directory. 640 if (!llvm::sys::fs::exists(mCacheDir.str()) && 641 llvm::sys::fs::create_directories(mCacheDir.str())) 642 { 643 SWR_INVALID("Unable to create directory: %s", mCacheDir.c_str()); 644 } 645 646} 647 648int ExecUnhookedProcess(const std::string& CmdLine, std::string* pStdOut, std::string* pStdErr) 649{ 650 return ExecCmd(CmdLine, "", pStdOut, pStdErr); 651} 652 653/// Calculate actual directory where module will be cached. 654/// This is always a subdirectory of mCacheDir. Full absolute 655/// path name will be stored in mCurrentModuleCacheDir 656void JitCache::CalcModuleCacheDir() 657{ 658 mModuleCacheDir.clear(); 659 660 llvm::SmallString<MAX_PATH> moduleDir = mCacheDir; 661 662 // Create 4 levels of directory hierarchy based on CRC, 256 entries each 663 uint8_t* pCRC = (uint8_t*)&mCurrentModuleCRC; 664 for (uint32_t i = 0; i < 4; ++i) 665 { 666 llvm::sys::path::append(moduleDir, std::to_string((int)pCRC[i])); 667 } 668 669 mModuleCacheDir = moduleDir; 670} 671 672 673/// notifyObjectCompiled - Provides a pointer to compiled code for Module M. 674void JitCache::notifyObjectCompiled(const llvm::Module* M, llvm::MemoryBufferRef Obj) 675{ 676 const std::string& moduleID = M->getModuleIdentifier(); 677 if (!moduleID.length()) 678 { 679 return; 680 } 681 682 if (!mModuleCacheDir.size()) 683 { 684 SWR_INVALID("Unset module cache directory"); 685 return; 686 } 687 688 if (!llvm::sys::fs::exists(mModuleCacheDir.str()) && 689 llvm::sys::fs::create_directories(mModuleCacheDir.str())) 690 { 691 SWR_INVALID("Unable to create directory: %s", mModuleCacheDir.c_str()); 692 return; 693 } 694 695 JitCacheFileHeader header; 696 697 llvm::SmallString<MAX_PATH> filePath = mModuleCacheDir; 698 llvm::sys::path::append(filePath, moduleID); 699 700 llvm::SmallString<MAX_PATH> objPath = filePath; 701 objPath += JIT_OBJ_EXT; 702 703 { 704 std::error_code err; 705 llvm::raw_fd_ostream fileObj(objPath.c_str(), err, llvm::sys::fs::F_None); 706 fileObj << Obj.getBuffer(); 707 fileObj.flush(); 708 } 709 710 711 { 712 std::error_code err; 713 llvm::raw_fd_ostream fileObj(filePath.c_str(), err, llvm::sys::fs::F_None); 714 715 uint32_t objcrc = ComputeCRC(0, Obj.getBufferStart(), Obj.getBufferSize()); 716 717 header.Init(mCurrentModuleCRC, objcrc, moduleID, mCpu, mOptLevel, Obj.getBufferSize()); 718 719 fileObj.write((const char*)&header, sizeof(header)); 720 fileObj.flush(); 721 } 722} 723 724/// Returns a pointer to a newly allocated MemoryBuffer that contains the 725/// object which corresponds with Module M, or 0 if an object is not 726/// available. 727std::unique_ptr<llvm::MemoryBuffer> JitCache::getObject(const llvm::Module* M) 728{ 729 const std::string& moduleID = M->getModuleIdentifier(); 730 mCurrentModuleCRC = ComputeModuleCRC(M); 731 732 if (!moduleID.length()) 733 { 734 return nullptr; 735 } 736 737 CalcModuleCacheDir(); 738 739 if (!llvm::sys::fs::exists(mModuleCacheDir)) 740 { 741 return nullptr; 742 } 743 744 llvm::SmallString<MAX_PATH> filePath = mModuleCacheDir; 745 llvm::sys::path::append(filePath, moduleID); 746 747 llvm::SmallString<MAX_PATH> objFilePath = filePath; 748 objFilePath += JIT_OBJ_EXT; 749 750 FILE* fpObjIn = nullptr; 751 FILE* fpIn = fopen(filePath.c_str(), "rb"); 752 if (!fpIn) 753 { 754 return nullptr; 755 } 756 757 std::unique_ptr<llvm::MemoryBuffer> pBuf = nullptr; 758 do 759 { 760 JitCacheFileHeader header; 761 if (!fread(&header, sizeof(header), 1, fpIn)) 762 { 763 break; 764 } 765 766 if (!header.IsValid(mCurrentModuleCRC, moduleID, mCpu, mOptLevel)) 767 { 768 break; 769 } 770 771 fpObjIn = fopen(objFilePath.c_str(), "rb"); 772 if (!fpObjIn) 773 { 774 break; 775 } 776 777#if LLVM_VERSION_MAJOR < 6 778 pBuf = llvm::MemoryBuffer::getNewUninitMemBuffer(size_t(header.GetObjectSize())); 779#else 780 pBuf = llvm::WritableMemoryBuffer::getNewUninitMemBuffer(size_t(header.GetObjectSize())); 781#endif 782 if (!fread(const_cast<char*>(pBuf->getBufferStart()), header.GetObjectSize(), 1, fpObjIn)) 783 { 784 pBuf = nullptr; 785 break; 786 } 787 788 if (header.GetObjectCRC() != ComputeCRC(0, pBuf->getBufferStart(), pBuf->getBufferSize())) 789 { 790 SWR_TRACE("Invalid object cache file, ignoring: %s", filePath.c_str()); 791 pBuf = nullptr; 792 break; 793 } 794 795 } while (0); 796 797 fclose(fpIn); 798 799 if (fpObjIn) 800 { 801 fclose(fpObjIn); 802 } 803 804 805 return pBuf; 806} 807 808void InterleaveAssemblyAnnotater::emitInstructionAnnot(const llvm::Instruction *pInst, llvm::formatted_raw_ostream &OS) 809{ 810 auto dbgLoc = pInst->getDebugLoc(); 811 if(dbgLoc) 812 { 813 unsigned int line = dbgLoc.getLine(); 814 if(line != mCurrentLineNo) 815 { 816 if(line > 0 && line <= mAssembly.size()) 817 { 818 // HACK: here we assume that OS is a formatted_raw_ostream(ods()) 819 // and modify the color accordingly. We can't do the color 820 // modification on OS because formatted_raw_ostream strips 821 // the color information. The only way to fix this behavior 822 // is to patch LLVM. 823 OS << "\n; " << line << ": " << mAssembly[line-1] << "\n"; 824 } 825 mCurrentLineNo = line; 826 } 827 } 828} 829 830