Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/swr/rasterizer/jitter/JitManager.cpp
4574 views
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
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),
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(_MSC_VER)
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
181
void 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.
212
void 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
224
DIType*
225
JitManager::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
270
DIType* 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
285
DIType* 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
#if LLVM_VERSION_MAJOR >= 11
317
case Type::FixedVectorTyID:
318
#else
319
case Type::VectorTyID:
320
#endif
321
return GetDebugVectorType(pTy);
322
break;
323
case Type::FunctionTyID:
324
return GetDebugFunctionType(pTy);
325
break;
326
default:
327
SWR_ASSERT(false, "Unimplemented llvm type");
328
}
329
return nullptr;
330
}
331
332
// Create a DISubroutineType from an llvm FunctionType
333
DIType* JitManager::GetDebugFunctionType(Type* pTy)
334
{
335
SmallVector<Metadata*, 8> ElemTypes;
336
FunctionType* pFuncTy = cast<FunctionType>(pTy);
337
DIBuilder builder(*mpCurrentModule);
338
339
// Add result type
340
ElemTypes.push_back(GetDebugType(pFuncTy->getReturnType()));
341
342
// Add arguments
343
for (auto& param : pFuncTy->params())
344
{
345
ElemTypes.push_back(GetDebugType(param));
346
}
347
348
return builder.createSubroutineType(builder.getOrCreateTypeArray(ElemTypes));
349
}
350
351
DIType* JitManager::GetDebugIntegerType(Type* pTy)
352
{
353
DIBuilder builder(*mpCurrentModule);
354
IntegerType* pIntTy = cast<IntegerType>(pTy);
355
switch (pIntTy->getBitWidth())
356
{
357
case 1:
358
return builder.createBasicType("int1", 1, dwarf::DW_ATE_unsigned);
359
break;
360
case 8:
361
return builder.createBasicType("int8", 8, dwarf::DW_ATE_signed);
362
break;
363
case 16:
364
return builder.createBasicType("int16", 16, dwarf::DW_ATE_signed);
365
break;
366
case 32:
367
return builder.createBasicType("int", 32, dwarf::DW_ATE_signed);
368
break;
369
case 64:
370
return builder.createBasicType("int64", 64, dwarf::DW_ATE_signed);
371
break;
372
case 128:
373
return builder.createBasicType("int128", 128, dwarf::DW_ATE_signed);
374
break;
375
default:
376
SWR_ASSERT(false, "Unimplemented integer bit width");
377
}
378
return nullptr;
379
}
380
381
DIType* JitManager::GetDebugVectorType(Type* pTy)
382
{
383
DIBuilder builder(*mpCurrentModule);
384
#if LLVM_VERSION_MAJOR >= 12
385
FixedVectorType* pVecTy = cast<FixedVectorType>(pTy);
386
#elif LLVM_VERSION_MAJOR >= 11
387
VectorType* pVecTy = cast<VectorType>(pTy);
388
#else
389
auto pVecTy = pTy;
390
#endif
391
DataLayout DL = DataLayout(mpCurrentModule);
392
uint32_t size = DL.getTypeAllocSizeInBits(pVecTy);
393
uint32_t alignment = DL.getABITypeAlignment(pVecTy);
394
SmallVector<Metadata*, 1> Elems;
395
396
#if LLVM_VERSION_MAJOR >= 11
397
Elems.push_back(builder.getOrCreateSubrange(0, pVecTy->getNumElements()));
398
#else
399
Elems.push_back(builder.getOrCreateSubrange(0, pVecTy->getVectorNumElements()));
400
#endif
401
402
return builder.createVectorType(size,
403
alignment,
404
#if LLVM_VERSION_MAJOR >= 11
405
GetDebugType(pVecTy->getElementType()),
406
#else
407
GetDebugType(pVecTy->getVectorElementType()),
408
#endif
409
builder.getOrCreateArray(Elems));
410
}
411
412
//////////////////////////////////////////////////////////////////////////
413
/// @brief Dump function x86 assembly to file.
414
/// @note This should only be called after the module has been jitted to x86 and the
415
/// module will not be further accessed.
416
void JitManager::DumpAsm(Function* pFunction, const char* fileName)
417
{
418
if (KNOB_DUMP_SHADER_IR)
419
{
420
#if defined(_WIN32)
421
DWORD pid = GetCurrentProcessId();
422
char procname[MAX_PATH];
423
GetModuleFileNameA(NULL, procname, MAX_PATH);
424
const char* pBaseName = strrchr(procname, '\\');
425
std::stringstream outDir;
426
outDir << JITTER_OUTPUT_DIR << pBaseName << "_" << pid << std::ends;
427
CreateDirectoryPath(outDir.str().c_str());
428
#endif
429
430
std::error_code EC;
431
Module* pModule = pFunction->getParent();
432
const char* funcName = pFunction->getName().data();
433
char fName[256];
434
#if defined(_WIN32)
435
sprintf(fName, "%s\\%s.%s.asm", outDir.str().c_str(), funcName, fileName);
436
#else
437
sprintf(fName, "%s.%s.asm", funcName, fileName);
438
#endif
439
440
raw_fd_ostream filestream(fName, EC, llvm::sys::fs::F_None);
441
442
legacy::PassManager* pMPasses = new legacy::PassManager();
443
auto* pTarget = mpExec->getTargetMachine();
444
pTarget->Options.MCOptions.AsmVerbose = true;
445
#if LLVM_VERSION_MAJOR >= 10
446
pTarget->addPassesToEmitFile(
447
*pMPasses, filestream, nullptr, CGFT_AssemblyFile);
448
#elif LLVM_VERSION_MAJOR >= 7
449
pTarget->addPassesToEmitFile(
450
*pMPasses, filestream, nullptr, TargetMachine::CGFT_AssemblyFile);
451
#else
452
pTarget->addPassesToEmitFile(*pMPasses, filestream, TargetMachine::CGFT_AssemblyFile);
453
#endif
454
pMPasses->run(*pModule);
455
delete pMPasses;
456
pTarget->Options.MCOptions.AsmVerbose = false;
457
}
458
}
459
460
std::string JitManager::GetOutputDir()
461
{
462
#if defined(_WIN32)
463
DWORD pid = GetCurrentProcessId();
464
char procname[MAX_PATH];
465
GetModuleFileNameA(NULL, procname, MAX_PATH);
466
const char* pBaseName = strrchr(procname, '\\');
467
std::stringstream outDir;
468
outDir << JITTER_OUTPUT_DIR << pBaseName << "_" << pid;
469
CreateDirectoryPath(outDir.str().c_str());
470
return outDir.str();
471
#endif
472
return "";
473
}
474
475
//////////////////////////////////////////////////////////////////////////
476
/// @brief Dump function to file.
477
void JitManager::DumpToFile(Module* M,
478
const char* fileName,
479
llvm::AssemblyAnnotationWriter* annotater)
480
{
481
if (KNOB_DUMP_SHADER_IR)
482
{
483
std::string outDir = GetOutputDir();
484
485
std::error_code EC;
486
const char* funcName = M->getName().data();
487
char fName[256];
488
#if defined(_WIN32)
489
sprintf(fName, "%s\\%s.%s.ll", outDir.c_str(), funcName, fileName);
490
#else
491
sprintf(fName, "%s.%s.ll", funcName, fileName);
492
#endif
493
raw_fd_ostream fd(fName, EC, llvm::sys::fs::F_None);
494
M->print(fd, annotater);
495
fd.flush();
496
}
497
}
498
499
//////////////////////////////////////////////////////////////////////////
500
/// @brief Dump function to file.
501
void JitManager::DumpToFile(Function* f, const char* fileName)
502
{
503
if (KNOB_DUMP_SHADER_IR)
504
{
505
std::string outDir = GetOutputDir();
506
507
std::error_code EC;
508
const char* funcName = f->getName().data();
509
char fName[256];
510
#if defined(_WIN32)
511
sprintf(fName, "%s\\%s.%s.ll", outDir.c_str(), funcName, fileName);
512
#else
513
sprintf(fName, "%s.%s.ll", funcName, fileName);
514
#endif
515
raw_fd_ostream fd(fName, EC, llvm::sys::fs::F_None);
516
f->print(fd, nullptr);
517
518
#if defined(_WIN32)
519
sprintf(fName, "%s\\cfg.%s.%s.dot", outDir.c_str(), funcName, fileName);
520
#else
521
sprintf(fName, "cfg.%s.%s.dot", funcName, fileName);
522
#endif
523
fd.flush();
524
525
raw_fd_ostream fd_cfg(fName, EC, llvm::sys::fs::F_Text);
526
WriteGraph(fd_cfg, (const Function*)f);
527
528
fd_cfg.flush();
529
}
530
}
531
532
extern "C" {
533
bool g_DllActive = true;
534
535
//////////////////////////////////////////////////////////////////////////
536
/// @brief Create JIT context.
537
/// @param simdWidth - SIMD width to be used in generated program.
538
HANDLE JITCALL JitCreateContext(uint32_t targetSimdWidth, const char* arch, const char* core)
539
{
540
return new JitManager(targetSimdWidth, arch, core);
541
}
542
543
//////////////////////////////////////////////////////////////////////////
544
/// @brief Destroy JIT context.
545
void JITCALL JitDestroyContext(HANDLE hJitContext)
546
{
547
if (g_DllActive)
548
{
549
delete reinterpret_cast<JitManager*>(hJitContext);
550
}
551
}
552
}
553
554
//////////////////////////////////////////////////////////////////////////
555
/// JitCache
556
//////////////////////////////////////////////////////////////////////////
557
558
//////////////////////////////////////////////////////////////////////////
559
/// JitCacheFileHeader
560
//////////////////////////////////////////////////////////////////////////
561
struct JitCacheFileHeader
562
{
563
void Init(uint32_t llCRC,
564
uint32_t objCRC,
565
const std::string& moduleID,
566
const std::string& cpu,
567
uint32_t optLevel,
568
uint64_t objSize)
569
{
570
m_objSize = objSize;
571
m_llCRC = llCRC;
572
m_objCRC = objCRC;
573
strncpy(m_ModuleID, moduleID.c_str(), JC_STR_MAX_LEN - 1);
574
m_ModuleID[JC_STR_MAX_LEN - 1] = 0;
575
strncpy(m_Cpu, cpu.c_str(), JC_STR_MAX_LEN - 1);
576
m_Cpu[JC_STR_MAX_LEN - 1] = 0;
577
m_optLevel = optLevel;
578
}
579
580
581
bool
582
IsValid(uint32_t llCRC, const std::string& moduleID, const std::string& cpu, uint32_t optLevel)
583
{
584
if ((m_MagicNumber != JC_MAGIC_NUMBER) || (m_llCRC != llCRC) ||
585
(m_platformKey != JC_PLATFORM_KEY) || (m_optLevel != optLevel))
586
{
587
return false;
588
}
589
590
m_ModuleID[JC_STR_MAX_LEN - 1] = 0;
591
if (strncmp(moduleID.c_str(), m_ModuleID, JC_STR_MAX_LEN - 1))
592
{
593
return false;
594
}
595
596
m_Cpu[JC_STR_MAX_LEN - 1] = 0;
597
if (strncmp(cpu.c_str(), m_Cpu, JC_STR_MAX_LEN - 1))
598
{
599
return false;
600
}
601
602
return true;
603
}
604
605
uint64_t GetObjectSize() const { return m_objSize; }
606
uint64_t GetObjectCRC() const { return m_objCRC; }
607
608
private:
609
static const uint64_t JC_MAGIC_NUMBER = 0xfedcba9876543210ULL + 7;
610
static const size_t JC_STR_MAX_LEN = 32;
611
static const uint32_t JC_PLATFORM_KEY = (LLVM_VERSION_MAJOR << 24) |
612
(LLVM_VERSION_MINOR << 16) | (LLVM_VERSION_PATCH << 8) |
613
((sizeof(void*) > sizeof(uint32_t)) ? 1 : 0);
614
615
uint64_t m_MagicNumber = JC_MAGIC_NUMBER;
616
uint64_t m_objSize = 0;
617
uint32_t m_llCRC = 0;
618
uint32_t m_platformKey = JC_PLATFORM_KEY;
619
uint32_t m_objCRC = 0;
620
uint32_t m_optLevel = 0;
621
char m_ModuleID[JC_STR_MAX_LEN] = {};
622
char m_Cpu[JC_STR_MAX_LEN] = {};
623
};
624
625
static inline uint32_t ComputeModuleCRC(const llvm::Module* M)
626
{
627
std::string bitcodeBuffer;
628
raw_string_ostream bitcodeStream(bitcodeBuffer);
629
630
#if LLVM_VERSION_MAJOR >= 7
631
llvm::WriteBitcodeToFile(*M, bitcodeStream);
632
#else
633
llvm::WriteBitcodeToFile(M, bitcodeStream);
634
#endif
635
// M->print(bitcodeStream, nullptr, false);
636
637
bitcodeStream.flush();
638
639
return ComputeCRC(0, bitcodeBuffer.data(), bitcodeBuffer.size());
640
}
641
642
/// constructor
643
JitCache::JitCache()
644
{
645
#if defined(__APPLE__) || defined(FORCE_LINUX) || defined(__linux__) || defined(__gnu_linux__)
646
if (strncmp(KNOB_JIT_CACHE_DIR.c_str(), "~/", 2) == 0)
647
{
648
char* homedir;
649
if (!(homedir = getenv("HOME")))
650
{
651
homedir = getpwuid(getuid())->pw_dir;
652
}
653
mCacheDir = homedir;
654
mCacheDir += (KNOB_JIT_CACHE_DIR.c_str() + 1);
655
}
656
else
657
#endif
658
{
659
mCacheDir = KNOB_JIT_CACHE_DIR;
660
}
661
662
// Create cache dir at startup to allow jitter to write debug.ll files
663
// to that directory.
664
if (!llvm::sys::fs::exists(mCacheDir.str()) &&
665
llvm::sys::fs::create_directories(mCacheDir.str()))
666
{
667
SWR_INVALID("Unable to create directory: %s", mCacheDir.c_str());
668
}
669
670
}
671
672
int ExecUnhookedProcess(const std::string& CmdLine, std::string* pStdOut, std::string* pStdErr)
673
{
674
675
return ExecCmd(CmdLine, nullptr, pStdOut, pStdErr);
676
}
677
678
/// Calculate actual directory where module will be cached.
679
/// This is always a subdirectory of mCacheDir. Full absolute
680
/// path name will be stored in mCurrentModuleCacheDir
681
void JitCache::CalcModuleCacheDir()
682
{
683
mModuleCacheDir.clear();
684
685
llvm::SmallString<MAX_PATH> moduleDir = mCacheDir;
686
687
// Create 4 levels of directory hierarchy based on CRC, 256 entries each
688
uint8_t* pCRC = (uint8_t*)&mCurrentModuleCRC;
689
for (uint32_t i = 0; i < 4; ++i)
690
{
691
llvm::sys::path::append(moduleDir, std::to_string((int)pCRC[i]));
692
}
693
694
mModuleCacheDir = moduleDir;
695
}
696
697
/// notifyObjectCompiled - Provides a pointer to compiled code for Module M.
698
void JitCache::notifyObjectCompiled(const llvm::Module* M, llvm::MemoryBufferRef Obj)
699
{
700
const std::string& moduleID = M->getModuleIdentifier();
701
if (!moduleID.length())
702
{
703
return;
704
}
705
706
if (!mModuleCacheDir.size())
707
{
708
SWR_INVALID("Unset module cache directory");
709
return;
710
}
711
712
if (!llvm::sys::fs::exists(mModuleCacheDir.str()) &&
713
llvm::sys::fs::create_directories(mModuleCacheDir.str()))
714
{
715
SWR_INVALID("Unable to create directory: %s", mModuleCacheDir.c_str());
716
return;
717
}
718
719
JitCacheFileHeader header;
720
721
llvm::SmallString<MAX_PATH> filePath = mModuleCacheDir;
722
llvm::sys::path::append(filePath, moduleID);
723
724
llvm::SmallString<MAX_PATH> objPath = filePath;
725
objPath += JIT_OBJ_EXT;
726
727
{
728
std::error_code err;
729
llvm::raw_fd_ostream fileObj(objPath.c_str(), err, llvm::sys::fs::F_None);
730
fileObj << Obj.getBuffer();
731
fileObj.flush();
732
}
733
734
735
{
736
std::error_code err;
737
llvm::raw_fd_ostream fileObj(filePath.c_str(), err, llvm::sys::fs::F_None);
738
739
uint32_t objcrc = ComputeCRC(0, Obj.getBufferStart(), Obj.getBufferSize());
740
741
header.Init(mCurrentModuleCRC, objcrc, moduleID, mCpu, mOptLevel, Obj.getBufferSize());
742
743
fileObj.write((const char*)&header, sizeof(header));
744
fileObj.flush();
745
}
746
}
747
748
/// Returns a pointer to a newly allocated MemoryBuffer that contains the
749
/// object which corresponds with Module M, or 0 if an object is not
750
/// available.
751
std::unique_ptr<llvm::MemoryBuffer> JitCache::getObject(const llvm::Module* M)
752
{
753
const std::string& moduleID = M->getModuleIdentifier();
754
mCurrentModuleCRC = ComputeModuleCRC(M);
755
756
if (!moduleID.length())
757
{
758
return nullptr;
759
}
760
761
CalcModuleCacheDir();
762
763
if (!llvm::sys::fs::exists(mModuleCacheDir))
764
{
765
return nullptr;
766
}
767
768
llvm::SmallString<MAX_PATH> filePath = mModuleCacheDir;
769
llvm::sys::path::append(filePath, moduleID);
770
771
llvm::SmallString<MAX_PATH> objFilePath = filePath;
772
objFilePath += JIT_OBJ_EXT;
773
774
FILE* fpObjIn = nullptr;
775
FILE* fpIn = fopen(filePath.c_str(), "rb");
776
if (!fpIn)
777
{
778
return nullptr;
779
}
780
781
std::unique_ptr<llvm::MemoryBuffer> pBuf = nullptr;
782
do
783
{
784
JitCacheFileHeader header;
785
if (!fread(&header, sizeof(header), 1, fpIn))
786
{
787
break;
788
}
789
790
if (!header.IsValid(mCurrentModuleCRC, moduleID, mCpu, mOptLevel))
791
{
792
break;
793
}
794
795
fpObjIn = fopen(objFilePath.c_str(), "rb");
796
if (!fpObjIn)
797
{
798
break;
799
}
800
801
#if LLVM_VERSION_MAJOR < 6
802
pBuf = llvm::MemoryBuffer::getNewUninitMemBuffer(size_t(header.GetObjectSize()));
803
#else
804
pBuf = llvm::WritableMemoryBuffer::getNewUninitMemBuffer(size_t(header.GetObjectSize()));
805
#endif
806
if (!fread(const_cast<char*>(pBuf->getBufferStart()), header.GetObjectSize(), 1, fpObjIn))
807
{
808
pBuf = nullptr;
809
break;
810
}
811
812
if (header.GetObjectCRC() != ComputeCRC(0, pBuf->getBufferStart(), pBuf->getBufferSize()))
813
{
814
SWR_TRACE("Invalid object cache file, ignoring: %s", filePath.c_str());
815
pBuf = nullptr;
816
break;
817
}
818
819
} while (0);
820
821
fclose(fpIn);
822
823
if (fpObjIn)
824
{
825
fclose(fpObjIn);
826
}
827
828
829
return pBuf;
830
}
831
832
void InterleaveAssemblyAnnotater::emitInstructionAnnot(const llvm::Instruction* pInst,
833
llvm::formatted_raw_ostream& OS)
834
{
835
auto dbgLoc = pInst->getDebugLoc();
836
if (dbgLoc)
837
{
838
unsigned int line = dbgLoc.getLine();
839
if (line != mCurrentLineNo)
840
{
841
if (line > 0 && line <= mAssembly.size())
842
{
843
// HACK: here we assume that OS is a formatted_raw_ostream(ods())
844
// and modify the color accordingly. We can't do the color
845
// modification on OS because formatted_raw_ostream strips
846
// the color information. The only way to fix this behavior
847
// is to patch LLVM.
848
OS << "\n; " << line << ": " << mAssembly[line - 1] << "\n";
849
}
850
mCurrentLineNo = line;
851
}
852
}
853
}
854
855