1 /****************************************************************************
2 * Copyright (C) 2014-2015 Intel Corporation. All Rights Reserved.
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:
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
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
23 * @file JitManager.cpp
25 * @brief Implementation if the Jit Manager.
29 ******************************************************************************/
30 #include "jit_pch.hpp"
32 #include "JitManager.h"
34 #include "fetch_jit.h"
36 #include "core/state.h"
38 #include "gen_state_llvm.h"
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"
50 #if defined(__APPLE__) || defined(FORCE_LINUX) || defined(__linux__) || defined(__gnu_linux__)
57 using namespace SwrJit
;
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
)
65 InitializeNativeTarget();
66 InitializeNativeTargetAsmPrinter();
67 InitializeNativeTargetDisassembler();
71 tOpts
.AllowFPOpFusion
= FPOpFusion::Fast
;
72 tOpts
.NoInfsFPMath
= false;
73 tOpts
.NoNaNsFPMath
= false;
74 tOpts
.UnsafeFPMath
= false;
76 //tOpts.PrintMachineCode = true;
78 std::unique_ptr
<Module
> newModule(new Module("", mContext
));
79 mpCurrentModule
= newModule
.get();
81 StringRef hostCPUName
;
83 hostCPUName
= sys::getHostCPUName();
86 // Needed for MCJIT on windows
87 Triple
hostTriple(sys::getProcessTriple());
88 hostTriple
.setObjectFormat(Triple::COFF
);
89 mpCurrentModule
->setTargetTriple(hostTriple
.getTriple());
92 auto optLevel
= CodeGenOpt::Aggressive
;
94 if (KNOB_JIT_OPTIMIZATION_LEVEL
>= CodeGenOpt::None
&&
95 KNOB_JIT_OPTIMIZATION_LEVEL
<= CodeGenOpt::Aggressive
)
97 optLevel
= CodeGenOpt::Level(KNOB_JIT_OPTIMIZATION_LEVEL
);
100 mpExec
= EngineBuilder(std::move(newModule
))
101 .setTargetOptions(tOpts
)
102 .setOptLevel(optLevel
)
103 .setMCPU(hostCPUName
)
106 if (KNOB_JIT_ENABLE_CACHE
)
108 mCache
.Init(this, hostCPUName
, optLevel
);
109 mpExec
->setObjectCache(&mCache
);
112 #if LLVM_USE_INTEL_JITEVENTS
113 JITEventListener
*vTune
= JITEventListener::createIntelJITEventListener();
114 mpExec
->RegisterJITEventListener(vTune
);
117 // fetch function signature
118 #if USE_SIMD16_SHADERS
119 // typedef void(__cdecl *PFN_FETCH_FUNC)(SWR_FETCH_CONTEXT& fetchInfo, simd16vertex& out);
121 // typedef void(__cdecl *PFN_FETCH_FUNC)(SWR_FETCH_CONTEXT& fetchInfo, simdvertex& out);
123 std::vector
<Type
*> fsArgs
;
125 // llvm5 is picky and does not take a void * type
126 fsArgs
.push_back(PointerType::get(Gen_SWR_FETCH_CONTEXT(this), 0));
128 fsArgs
.push_back(PointerType::get(Gen_SWR_FETCH_CONTEXT(this), 0));
129 #if USE_SIMD16_SHADERS
130 fsArgs
.push_back(PointerType::get(Gen_simd16vertex(this), 0));
132 fsArgs
.push_back(PointerType::get(Gen_simdvertex(this), 0));
135 mFetchShaderTy
= FunctionType::get(Type::getVoidTy(mContext
), fsArgs
, false);
138 // explicitly instantiate used symbols from potentially staticly linked libs
139 sys::DynamicLibrary::AddSymbol("exp2f", &exp2f
);
140 sys::DynamicLibrary::AddSymbol("log2f", &log2f
);
141 sys::DynamicLibrary::AddSymbol("sinf", &sinf
);
142 sys::DynamicLibrary::AddSymbol("cosf", &cosf
);
143 sys::DynamicLibrary::AddSymbol("powf", &powf
);
147 if (KNOB_DUMP_SHADER_IR
)
149 CreateDirectoryPath(INTEL_OUTPUT_DIR
);
150 CreateDirectoryPath(SWR_OUTPUT_DIR
);
151 CreateDirectoryPath(JITTER_OUTPUT_DIR
);
156 //////////////////////////////////////////////////////////////////////////
157 /// @brief Create new LLVM module.
158 void JitManager::SetupNewModule()
160 SWR_ASSERT(mIsModuleFinalized
== true && "Current module is not finalized!");
162 std::unique_ptr
<Module
> newModule(new Module("", mContext
));
163 mpCurrentModule
= newModule
.get();
165 // Needed for MCJIT on windows
166 Triple
hostTriple(sys::getProcessTriple());
167 hostTriple
.setObjectFormat(Triple::COFF
);
168 newModule
->setTargetTriple(hostTriple
.getTriple());
171 mpExec
->addModule(std::move(newModule
));
172 mIsModuleFinalized
= false;
176 DIType
* JitManager::CreateDebugStructType(StructType
* pType
, const std::string
& name
, DIFile
* pFile
, uint32_t lineNum
,
177 const std::vector
<std::pair
<std::string
, uint32_t>>& members
)
179 DIBuilder
builder(*mpCurrentModule
);
180 SmallVector
<Metadata
*, 8> ElemTypes
;
181 DataLayout DL
= DataLayout(mpCurrentModule
);
182 uint32_t size
= DL
.getTypeAllocSizeInBits(pType
);
183 uint32_t alignment
= DL
.getABITypeAlignment(pType
);
184 DINode::DIFlags flags
= DINode::DIFlags::FlagPublic
;
186 DICompositeType
* pDIStructTy
= builder
.createStructType(pFile
, name
, pFile
, lineNum
, size
, alignment
,
187 flags
, nullptr, builder
.getOrCreateArray(ElemTypes
));
189 // Register mapping now to break loops (in case struct contains itself or pointers to itself)
190 mDebugStructMap
[pType
] = pDIStructTy
;
193 for (auto& elem
: pType
->elements())
195 std::string name
= members
[idx
].first
;
196 uint32_t lineNum
= members
[idx
].second
;
197 size
= DL
.getTypeAllocSizeInBits(elem
);
198 alignment
= DL
.getABITypeAlignment(elem
);
199 uint32_t offset
= DL
.getStructLayout(pType
)->getElementOffsetInBits(idx
);
200 llvm::DIType
* pDebugTy
= GetDebugType(elem
);
201 ElemTypes
.push_back(builder
.createMemberType(pDIStructTy
, name
, pFile
, lineNum
, size
, alignment
, offset
, flags
, pDebugTy
));
206 pDIStructTy
->replaceElements(builder
.getOrCreateArray(ElemTypes
));
210 DIType
* JitManager::GetDebugArrayType(Type
* pTy
)
212 DIBuilder
builder(*mpCurrentModule
);
213 DataLayout DL
= DataLayout(mpCurrentModule
);
214 ArrayType
* pArrayTy
= cast
<ArrayType
>(pTy
);
215 uint32_t size
= DL
.getTypeAllocSizeInBits(pArrayTy
);
216 uint32_t alignment
= DL
.getABITypeAlignment(pArrayTy
);
218 SmallVector
<Metadata
*, 8> Elems
;
219 Elems
.push_back(builder
.getOrCreateSubrange(0, pArrayTy
->getNumElements()));
220 return builder
.createArrayType(size
, alignment
, GetDebugType(pArrayTy
->getElementType()), builder
.getOrCreateArray(Elems
));
223 // Create a DIType from llvm Type
224 DIType
* JitManager::GetDebugType(Type
* pTy
)
226 DIBuilder
builder(*mpCurrentModule
);
227 Type::TypeID id
= pTy
->getTypeID();
231 case Type::VoidTyID
: return builder
.createUnspecifiedType("void"); break;
232 case Type::HalfTyID
: return builder
.createBasicType("float16", 16, dwarf::DW_ATE_float
); break;
233 case Type::FloatTyID
: return builder
.createBasicType("float", 32, dwarf::DW_ATE_float
); break;
234 case Type::DoubleTyID
: return builder
.createBasicType("double", 64, dwarf::DW_ATE_float
); break;
235 case Type::IntegerTyID
: return GetDebugIntegerType(pTy
); break;
236 case Type::StructTyID
: return GetDebugStructType(pTy
); break;
237 case Type::ArrayTyID
: return GetDebugArrayType(pTy
); break;
238 case Type::PointerTyID
: return builder
.createPointerType(GetDebugType(pTy
->getPointerElementType()), 64, 64); break;
239 case Type::VectorTyID
: return GetDebugVectorType(pTy
); break;
240 case Type::FunctionTyID
: return GetDebugFunctionType(pTy
); break;
241 default: SWR_ASSERT(false, "Unimplemented llvm type");
246 // Create a DISubroutineType from an llvm FunctionType
247 DIType
* JitManager::GetDebugFunctionType(Type
* pTy
)
249 SmallVector
<Metadata
*, 8> ElemTypes
;
250 FunctionType
* pFuncTy
= cast
<FunctionType
>(pTy
);
251 DIBuilder
builder(*mpCurrentModule
);
254 ElemTypes
.push_back(GetDebugType(pFuncTy
->getReturnType()));
257 for (auto& param
: pFuncTy
->params())
259 ElemTypes
.push_back(GetDebugType(param
));
262 return builder
.createSubroutineType(builder
.getOrCreateTypeArray(ElemTypes
));
265 DIType
* JitManager::GetDebugIntegerType(Type
* pTy
)
267 DIBuilder
builder(*mpCurrentModule
);
268 IntegerType
* pIntTy
= cast
<IntegerType
>(pTy
);
269 switch (pIntTy
->getBitWidth())
271 case 1: return builder
.createBasicType("int1", 1, dwarf::DW_ATE_unsigned
); break;
272 case 8: return builder
.createBasicType("int8", 8, dwarf::DW_ATE_signed
); break;
273 case 16: return builder
.createBasicType("int16", 16, dwarf::DW_ATE_signed
); break;
274 case 32: return builder
.createBasicType("int", 32, dwarf::DW_ATE_signed
); break;
275 case 64: return builder
.createBasicType("int64", 64, dwarf::DW_ATE_signed
); break;
276 case 128: return builder
.createBasicType("int128", 128, dwarf::DW_ATE_signed
); break;
277 default: SWR_ASSERT(false, "Unimplemented integer bit width");
282 DIType
* JitManager::GetDebugVectorType(Type
* pTy
)
284 DIBuilder
builder(*mpCurrentModule
);
285 VectorType
* pVecTy
= cast
<VectorType
>(pTy
);
286 DataLayout DL
= DataLayout(mpCurrentModule
);
287 uint32_t size
= DL
.getTypeAllocSizeInBits(pVecTy
);
288 uint32_t alignment
= DL
.getABITypeAlignment(pVecTy
);
289 SmallVector
<Metadata
*, 1> Elems
;
290 Elems
.push_back(builder
.getOrCreateSubrange(0, pVecTy
->getVectorNumElements()));
292 return builder
.createVectorType(size
, alignment
, GetDebugType(pVecTy
->getVectorElementType()), builder
.getOrCreateArray(Elems
));
296 //////////////////////////////////////////////////////////////////////////
297 /// @brief Dump function x86 assembly to file.
298 /// @note This should only be called after the module has been jitted to x86 and the
299 /// module will not be further accessed.
300 void JitManager::DumpAsm(Function
* pFunction
, const char* fileName
)
302 if (KNOB_DUMP_SHADER_IR
)
306 DWORD pid
= GetCurrentProcessId();
307 char procname
[MAX_PATH
];
308 GetModuleFileNameA(NULL
, procname
, MAX_PATH
);
309 const char* pBaseName
= strrchr(procname
, '\\');
310 std::stringstream outDir
;
311 outDir
<< JITTER_OUTPUT_DIR
<< pBaseName
<< "_" << pid
<< std::ends
;
312 CreateDirectoryPath(outDir
.str().c_str());
316 Module
* pModule
= pFunction
->getParent();
317 const char *funcName
= pFunction
->getName().data();
320 sprintf(fName
, "%s\\%s.%s.asm", outDir
.str().c_str(), funcName
, fileName
);
322 sprintf(fName
, "%s.%s.asm", funcName
, fileName
);
325 raw_fd_ostream
filestream(fName
, EC
, llvm::sys::fs::F_None
);
327 legacy::PassManager
* pMPasses
= new legacy::PassManager();
328 auto* pTarget
= mpExec
->getTargetMachine();
329 pTarget
->Options
.MCOptions
.AsmVerbose
= true;
330 pTarget
->addPassesToEmitFile(*pMPasses
, filestream
, TargetMachine::CGFT_AssemblyFile
);
331 pMPasses
->run(*pModule
);
333 pTarget
->Options
.MCOptions
.AsmVerbose
= false;
337 std::string
JitManager::GetOutputDir()
340 DWORD pid
= GetCurrentProcessId();
341 char procname
[MAX_PATH
];
342 GetModuleFileNameA(NULL
, procname
, MAX_PATH
);
343 const char* pBaseName
= strrchr(procname
, '\\');
344 std::stringstream outDir
;
345 outDir
<< JITTER_OUTPUT_DIR
<< pBaseName
<< "_" << pid
;
346 CreateDirectoryPath(outDir
.str().c_str());
352 //////////////////////////////////////////////////////////////////////////
353 /// @brief Dump function to file.
354 void JitManager::DumpToFile(Module
*M
, const char *fileName
)
356 if (KNOB_DUMP_SHADER_IR
)
358 std::string outDir
= GetOutputDir();
361 const char *funcName
= M
->getName().data();
364 sprintf(fName
, "%s\\%s.%s.ll", outDir
.c_str(), funcName
, fileName
);
366 sprintf(fName
, "%s.%s.ll", funcName
, fileName
);
368 raw_fd_ostream
fd(fName
, EC
, llvm::sys::fs::F_None
);
369 M
->print(fd
, nullptr);
374 //////////////////////////////////////////////////////////////////////////
375 /// @brief Dump function to file.
376 void JitManager::DumpToFile(Function
*f
, const char *fileName
)
378 if (KNOB_DUMP_SHADER_IR
)
380 std::string outDir
= GetOutputDir();
383 const char *funcName
= f
->getName().data();
386 sprintf(fName
, "%s\\%s.%s.ll", outDir
.c_str(), funcName
, fileName
);
388 sprintf(fName
, "%s.%s.ll", funcName
, fileName
);
390 raw_fd_ostream
fd(fName
, EC
, llvm::sys::fs::F_None
);
391 f
->print(fd
, nullptr);
394 sprintf(fName
, "%s\\cfg.%s.%s.dot", outDir
.c_str(), funcName
, fileName
);
396 sprintf(fName
, "cfg.%s.%s.dot", funcName
, fileName
);
400 raw_fd_ostream
fd_cfg(fName
, EC
, llvm::sys::fs::F_Text
);
401 WriteGraph(fd_cfg
, (const Function
*)f
);
409 bool g_DllActive
= true;
411 //////////////////////////////////////////////////////////////////////////
412 /// @brief Create JIT context.
413 /// @param simdWidth - SIMD width to be used in generated program.
414 HANDLE JITCALL
JitCreateContext(uint32_t targetSimdWidth
, const char* arch
, const char* core
)
416 return new JitManager(targetSimdWidth
, arch
, core
);
419 //////////////////////////////////////////////////////////////////////////
420 /// @brief Destroy JIT context.
421 void JITCALL
JitDestroyContext(HANDLE hJitContext
)
425 delete reinterpret_cast<JitManager
*>(hJitContext
);
430 //////////////////////////////////////////////////////////////////////////
432 //////////////////////////////////////////////////////////////////////////
434 //////////////////////////////////////////////////////////////////////////
435 /// JitCacheFileHeader
436 //////////////////////////////////////////////////////////////////////////
437 struct JitCacheFileHeader
442 const std::string
& moduleID
,
443 const std::string
& cpu
,
450 strncpy(m_ModuleID
, moduleID
.c_str(), JC_STR_MAX_LEN
- 1);
451 m_ModuleID
[JC_STR_MAX_LEN
- 1] = 0;
452 strncpy(m_Cpu
, cpu
.c_str(), JC_STR_MAX_LEN
- 1);
453 m_Cpu
[JC_STR_MAX_LEN
- 1] = 0;
454 m_optLevel
= optLevel
;
458 bool IsValid(uint32_t llCRC
, const std::string
& moduleID
, const std::string
& cpu
, uint32_t optLevel
)
460 if ((m_MagicNumber
!= JC_MAGIC_NUMBER
) ||
461 (m_llCRC
!= llCRC
) ||
462 (m_platformKey
!= JC_PLATFORM_KEY
) ||
463 (m_optLevel
!= optLevel
))
468 m_ModuleID
[JC_STR_MAX_LEN
- 1] = 0;
469 if (strncmp(moduleID
.c_str(), m_ModuleID
, JC_STR_MAX_LEN
- 1))
474 m_Cpu
[JC_STR_MAX_LEN
- 1] = 0;
475 if (strncmp(cpu
.c_str(), m_Cpu
, JC_STR_MAX_LEN
- 1))
483 uint64_t GetObjectSize() const { return m_objSize
; }
484 uint64_t GetObjectCRC() const { return m_objCRC
; }
487 static const uint64_t JC_MAGIC_NUMBER
= 0xfedcba9876543211ULL
+ 3;
488 static const size_t JC_STR_MAX_LEN
= 32;
489 static const uint32_t JC_PLATFORM_KEY
=
490 (LLVM_VERSION_MAJOR
<< 24) |
491 (LLVM_VERSION_MINOR
<< 16) |
492 (LLVM_VERSION_PATCH
<< 8) |
493 ((sizeof(void*) > sizeof(uint32_t)) ? 1 : 0);
495 uint64_t m_MagicNumber
= JC_MAGIC_NUMBER
;
496 uint64_t m_objSize
= 0;
497 uint32_t m_llCRC
= 0;
498 uint32_t m_platformKey
= JC_PLATFORM_KEY
;
499 uint32_t m_objCRC
= 0;
500 uint32_t m_optLevel
= 0;
501 char m_ModuleID
[JC_STR_MAX_LEN
] = {};
502 char m_Cpu
[JC_STR_MAX_LEN
] = {};
505 static inline uint32_t ComputeModuleCRC(const llvm::Module
* M
)
507 std::string bitcodeBuffer
;
508 raw_string_ostream
bitcodeStream(bitcodeBuffer
);
510 llvm::WriteBitcodeToFile(M
, bitcodeStream
);
511 //M->print(bitcodeStream, nullptr, false);
513 bitcodeStream
.flush();
515 return ComputeCRC(0, bitcodeBuffer
.data(), bitcodeBuffer
.size());
521 #if defined(__APPLE__) || defined(FORCE_LINUX) || defined(__linux__) || defined(__gnu_linux__)
522 if (strncmp(KNOB_JIT_CACHE_DIR
.c_str(), "~/", 2) == 0) {
524 if (!(homedir
= getenv("HOME"))) {
525 homedir
= getpwuid(getuid())->pw_dir
;
528 mCacheDir
+= (KNOB_JIT_CACHE_DIR
.c_str() + 1);
532 mCacheDir
= KNOB_JIT_CACHE_DIR
;
536 int ExecUnhookedProcess(const std::string
& CmdLine
, std::string
* pStdOut
, std::string
* pStdErr
)
538 static const char *g_pEnv
= "RASTY_DISABLE_HOOK=1\0";
540 return ExecCmd(CmdLine
, g_pEnv
, pStdOut
, pStdErr
);
544 /// notifyObjectCompiled - Provides a pointer to compiled code for Module M.
545 void JitCache::notifyObjectCompiled(const llvm::Module
*M
, llvm::MemoryBufferRef Obj
)
547 const std::string
& moduleID
= M
->getModuleIdentifier();
548 if (!moduleID
.length())
553 if (!llvm::sys::fs::exists(mCacheDir
.str()) &&
554 llvm::sys::fs::create_directories(mCacheDir
.str()))
556 SWR_INVALID("Unable to create directory: %s", mCacheDir
.c_str());
560 JitCacheFileHeader header
;
562 llvm::SmallString
<MAX_PATH
> filePath
= mCacheDir
;
563 llvm::sys::path::append(filePath
, moduleID
);
565 llvm::SmallString
<MAX_PATH
> objPath
= filePath
;
566 objPath
+= JIT_OBJ_EXT
;
570 llvm::raw_fd_ostream
fileObj(objPath
.c_str(), err
, llvm::sys::fs::F_None
);
571 fileObj
<< Obj
.getBuffer();
578 llvm::raw_fd_ostream
fileObj(filePath
.c_str(), err
, llvm::sys::fs::F_None
);
580 uint32_t objcrc
= ComputeCRC(0, Obj
.getBufferStart(), Obj
.getBufferSize());
582 header
.Init(mCurrentModuleCRC
, objcrc
, moduleID
, mCpu
, mOptLevel
, Obj
.getBufferSize());
584 fileObj
.write((const char*)&header
, sizeof(header
));
589 /// Returns a pointer to a newly allocated MemoryBuffer that contains the
590 /// object which corresponds with Module M, or 0 if an object is not
592 std::unique_ptr
<llvm::MemoryBuffer
> JitCache::getObject(const llvm::Module
* M
)
594 const std::string
& moduleID
= M
->getModuleIdentifier();
595 mCurrentModuleCRC
= ComputeModuleCRC(M
);
597 if (!moduleID
.length())
602 if (!llvm::sys::fs::exists(mCacheDir
))
607 llvm::SmallString
<MAX_PATH
> filePath
= mCacheDir
;
608 llvm::sys::path::append(filePath
, moduleID
);
610 llvm::SmallString
<MAX_PATH
> objFilePath
= filePath
;
611 objFilePath
+= JIT_OBJ_EXT
;
613 FILE* fpObjIn
= nullptr;
614 FILE* fpIn
= fopen(filePath
.c_str(), "rb");
620 std::unique_ptr
<llvm::MemoryBuffer
> pBuf
= nullptr;
623 JitCacheFileHeader header
;
624 if (!fread(&header
, sizeof(header
), 1, fpIn
))
629 if (!header
.IsValid(mCurrentModuleCRC
, moduleID
, mCpu
, mOptLevel
))
634 fpObjIn
= fopen(objFilePath
.c_str(), "rb");
640 #if LLVM_VERSION_MAJOR < 6
641 pBuf
= llvm::MemoryBuffer::getNewUninitMemBuffer(size_t(header
.GetObjectSize()));
643 pBuf
= llvm::WritableMemoryBuffer::getNewUninitMemBuffer(size_t(header
.GetObjectSize()));
645 if (!fread(const_cast<char*>(pBuf
->getBufferStart()), header
.GetObjectSize(), 1, fpObjIn
))
651 if (header
.GetObjectCRC() != ComputeCRC(0, pBuf
->getBufferStart(), pBuf
->getBufferSize()))
653 SWR_TRACE("Invalid object cache file, ignoring: %s", filePath
.c_str());