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();
70 tOpts
.AllowFPOpFusion
= FPOpFusion::Fast
;
71 tOpts
.NoInfsFPMath
= false;
72 tOpts
.NoNaNsFPMath
= false;
73 tOpts
.UnsafeFPMath
= false;
75 #if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7
76 tOpts
.NoFramePointerElim
= true;
80 //tOpts.PrintMachineCode = true;
82 mCore
= std::string(core
);
83 std::transform(mCore
.begin(), mCore
.end(), mCore
.begin(), ::tolower
);
85 std::unique_ptr
<Module
> newModule(new Module("", mContext
));
86 mpCurrentModule
= newModule
.get();
88 StringRef hostCPUName
;
90 hostCPUName
= sys::getHostCPUName();
93 // Needed for MCJIT on windows
94 Triple
hostTriple(sys::getProcessTriple());
95 hostTriple
.setObjectFormat(Triple::COFF
);
96 mpCurrentModule
->setTargetTriple(hostTriple
.getTriple());
99 mpExec
= EngineBuilder(std::move(newModule
))
100 .setTargetOptions(tOpts
)
101 .setOptLevel(CodeGenOpt::Aggressive
)
102 .setMCPU(hostCPUName
)
105 if (KNOB_JIT_ENABLE_CACHE
)
107 mCache
.SetCpu(hostCPUName
);
108 mpExec
->setObjectCache(&mCache
);
111 #if LLVM_USE_INTEL_JITEVENTS
112 JITEventListener
*vTune
= JITEventListener::createIntelJITEventListener();
113 mpExec
->RegisterJITEventListener(vTune
);
116 mFP32Ty
= Type::getFloatTy(mContext
); // float type
117 mInt8Ty
= Type::getInt8Ty(mContext
);
118 mInt32Ty
= Type::getInt32Ty(mContext
); // int type
119 mInt64Ty
= Type::getInt64Ty(mContext
); // int type
121 // fetch function signature
122 #if USE_SIMD16_SHADERS
123 // typedef void(__cdecl *PFN_FETCH_FUNC)(SWR_FETCH_CONTEXT& fetchInfo, simd16vertex& out);
125 // typedef void(__cdecl *PFN_FETCH_FUNC)(SWR_FETCH_CONTEXT& fetchInfo, simdvertex& out);
127 std::vector
<Type
*> fsArgs
;
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);
137 mSimtFP32Ty
= VectorType::get(mFP32Ty
, mVWidth
);
138 mSimtInt32Ty
= VectorType::get(mInt32Ty
, mVWidth
);
140 mSimdVectorTy
= ArrayType::get(mSimtFP32Ty
, 4);
141 mSimdVectorInt32Ty
= ArrayType::get(mSimtInt32Ty
, 4);
143 #if USE_SIMD16_SHADERS
144 mSimd16FP32Ty
= ArrayType::get(mSimtFP32Ty
, 2);
145 mSimd16Int32Ty
= ArrayType::get(mSimtInt32Ty
, 2);
147 mSimd16VectorFP32Ty
= ArrayType::get(mSimd16FP32Ty
, 4);
148 mSimd16VectorInt32Ty
= ArrayType::get(mSimd16Int32Ty
, 4);
152 // explicitly instantiate used symbols from potentially staticly linked libs
153 sys::DynamicLibrary::AddSymbol("exp2f", &exp2f
);
154 sys::DynamicLibrary::AddSymbol("log2f", &log2f
);
155 sys::DynamicLibrary::AddSymbol("sinf", &sinf
);
156 sys::DynamicLibrary::AddSymbol("cosf", &cosf
);
157 sys::DynamicLibrary::AddSymbol("powf", &powf
);
161 if (KNOB_DUMP_SHADER_IR
)
163 CreateDirectoryPath(INTEL_OUTPUT_DIR
);
164 CreateDirectoryPath(SWR_OUTPUT_DIR
);
165 CreateDirectoryPath(JITTER_OUTPUT_DIR
);
170 //////////////////////////////////////////////////////////////////////////
171 /// @brief Create new LLVM module.
172 void JitManager::SetupNewModule()
174 SWR_ASSERT(mIsModuleFinalized
== true && "Current module is not finalized!");
176 std::unique_ptr
<Module
> newModule(new Module("", mContext
));
177 mpCurrentModule
= newModule
.get();
179 // Needed for MCJIT on windows
180 Triple
hostTriple(sys::getProcessTriple());
181 hostTriple
.setObjectFormat(Triple::COFF
);
182 newModule
->setTargetTriple(hostTriple
.getTriple());
185 mpExec
->addModule(std::move(newModule
));
186 mIsModuleFinalized
= false;
190 //////////////////////////////////////////////////////////////////////////
191 /// @brief Dump function x86 assembly to file.
192 /// @note This should only be called after the module has been jitted to x86 and the
193 /// module will not be further accessed.
194 void JitManager::DumpAsm(Function
* pFunction
, const char* fileName
)
196 if (KNOB_DUMP_SHADER_IR
)
200 DWORD pid
= GetCurrentProcessId();
201 char procname
[MAX_PATH
];
202 GetModuleFileNameA(NULL
, procname
, MAX_PATH
);
203 const char* pBaseName
= strrchr(procname
, '\\');
204 std::stringstream outDir
;
205 outDir
<< JITTER_OUTPUT_DIR
<< pBaseName
<< "_" << pid
<< std::ends
;
206 CreateDirectoryPath(outDir
.str().c_str());
210 Module
* pModule
= pFunction
->getParent();
211 const char *funcName
= pFunction
->getName().data();
214 sprintf(fName
, "%s\\%s.%s.asm", outDir
.str().c_str(), funcName
, fileName
);
216 sprintf(fName
, "%s.%s.asm", funcName
, fileName
);
219 raw_fd_ostream
filestream(fName
, EC
, llvm::sys::fs::F_None
);
221 legacy::PassManager
* pMPasses
= new legacy::PassManager();
222 auto* pTarget
= mpExec
->getTargetMachine();
223 pTarget
->Options
.MCOptions
.AsmVerbose
= true;
224 pTarget
->addPassesToEmitFile(*pMPasses
, filestream
, TargetMachine::CGFT_AssemblyFile
);
225 pMPasses
->run(*pModule
);
227 pTarget
->Options
.MCOptions
.AsmVerbose
= false;
231 //////////////////////////////////////////////////////////////////////////
232 /// @brief Dump function to file.
233 void JitManager::DumpToFile(Function
*f
, const char *fileName
)
235 if (KNOB_DUMP_SHADER_IR
)
238 DWORD pid
= GetCurrentProcessId();
239 char procname
[MAX_PATH
];
240 GetModuleFileNameA(NULL
, procname
, MAX_PATH
);
241 const char* pBaseName
= strrchr(procname
, '\\');
242 std::stringstream outDir
;
243 outDir
<< JITTER_OUTPUT_DIR
<< pBaseName
<< "_" << pid
<< std::ends
;
244 CreateDirectoryPath(outDir
.str().c_str());
248 const char *funcName
= f
->getName().data();
251 sprintf(fName
, "%s\\%s.%s.ll", outDir
.str().c_str(), funcName
, fileName
);
253 sprintf(fName
, "%s.%s.ll", funcName
, fileName
);
255 raw_fd_ostream
fd(fName
, EC
, llvm::sys::fs::F_None
);
256 Module
* pModule
= f
->getParent();
257 pModule
->print(fd
, nullptr);
260 sprintf(fName
, "%s\\cfg.%s.%s.dot", outDir
.str().c_str(), funcName
, fileName
);
262 sprintf(fName
, "cfg.%s.%s.dot", funcName
, fileName
);
266 raw_fd_ostream
fd_cfg(fName
, EC
, llvm::sys::fs::F_Text
);
267 WriteGraph(fd_cfg
, (const Function
*)f
);
275 bool g_DllActive
= true;
277 //////////////////////////////////////////////////////////////////////////
278 /// @brief Create JIT context.
279 /// @param simdWidth - SIMD width to be used in generated program.
280 HANDLE JITCALL
JitCreateContext(uint32_t targetSimdWidth
, const char* arch
, const char* core
)
282 return new JitManager(targetSimdWidth
, arch
, core
);
285 //////////////////////////////////////////////////////////////////////////
286 /// @brief Destroy JIT context.
287 void JITCALL
JitDestroyContext(HANDLE hJitContext
)
291 delete reinterpret_cast<JitManager
*>(hJitContext
);
296 //////////////////////////////////////////////////////////////////////////
298 //////////////////////////////////////////////////////////////////////////
300 //////////////////////////////////////////////////////////////////////////
301 /// JitCacheFileHeader
302 //////////////////////////////////////////////////////////////////////////
303 struct JitCacheFileHeader
305 void Init(uint32_t llCRC
, uint32_t objCRC
, const std::string
& moduleID
, const std::string
& cpu
, uint64_t bufferSize
)
307 m_MagicNumber
= JC_MAGIC_NUMBER
;
308 m_BufferSize
= bufferSize
;
310 m_platformKey
= JC_PLATFORM_KEY
;
312 strncpy(m_ModuleID
, moduleID
.c_str(), JC_STR_MAX_LEN
- 1);
313 m_ModuleID
[JC_STR_MAX_LEN
- 1] = 0;
314 strncpy(m_Cpu
, cpu
.c_str(), JC_STR_MAX_LEN
- 1);
315 m_Cpu
[JC_STR_MAX_LEN
- 1] = 0;
318 bool IsValid(uint32_t llCRC
, const std::string
& moduleID
, const std::string
& cpu
)
320 if ((m_MagicNumber
!= JC_MAGIC_NUMBER
) ||
321 (m_llCRC
!= llCRC
) ||
322 (m_platformKey
!= JC_PLATFORM_KEY
))
327 m_ModuleID
[JC_STR_MAX_LEN
- 1] = 0;
328 if (strncmp(moduleID
.c_str(), m_ModuleID
, JC_STR_MAX_LEN
- 1))
333 m_Cpu
[JC_STR_MAX_LEN
- 1] = 0;
334 if (strncmp(cpu
.c_str(), m_Cpu
, JC_STR_MAX_LEN
- 1))
342 uint64_t GetBufferSize() const { return m_BufferSize
; }
343 uint64_t GetBufferCRC() const { return m_objCRC
; }
346 static const uint64_t JC_MAGIC_NUMBER
= 0xfedcba9876543211ULL
;
347 static const size_t JC_STR_MAX_LEN
= 32;
348 static const uint32_t JC_PLATFORM_KEY
=
349 (LLVM_VERSION_MAJOR
<< 24) |
350 (LLVM_VERSION_MINOR
<< 16) |
351 (LLVM_VERSION_PATCH
<< 8) |
352 ((sizeof(void*) > sizeof(uint32_t)) ? 1 : 0);
354 uint64_t m_MagicNumber
;
355 uint64_t m_BufferSize
;
357 uint32_t m_platformKey
;
359 char m_ModuleID
[JC_STR_MAX_LEN
];
360 char m_Cpu
[JC_STR_MAX_LEN
];
363 static inline uint32_t ComputeModuleCRC(const llvm::Module
* M
)
365 std::string bitcodeBuffer
;
366 raw_string_ostream
bitcodeStream(bitcodeBuffer
);
368 llvm::WriteBitcodeToFile(M
, bitcodeStream
);
369 //M->print(bitcodeStream, nullptr, false);
371 bitcodeStream
.flush();
373 return ComputeCRC(0, bitcodeBuffer
.data(), bitcodeBuffer
.size());
379 #if defined(__APPLE) || defined(FORCE_LINUX) || defined(__linux__) || defined(__gnu_linux__)
380 if (strncmp(KNOB_JIT_CACHE_DIR
.c_str(), "~/", 2) == 0) {
382 if (!(homedir
= getenv("HOME"))) {
383 homedir
= getpwuid(getuid())->pw_dir
;
386 mCacheDir
+= (KNOB_JIT_CACHE_DIR
.c_str() + 1);
390 mCacheDir
= KNOB_JIT_CACHE_DIR
;
394 /// notifyObjectCompiled - Provides a pointer to compiled code for Module M.
395 void JitCache::notifyObjectCompiled(const llvm::Module
*M
, llvm::MemoryBufferRef Obj
)
397 const std::string
& moduleID
= M
->getModuleIdentifier();
398 if (!moduleID
.length())
403 if (!llvm::sys::fs::exists(mCacheDir
.str()) &&
404 llvm::sys::fs::create_directories(mCacheDir
.str()))
406 SWR_INVALID("Unable to create directory: %s", mCacheDir
.c_str());
410 llvm::SmallString
<MAX_PATH
> filePath
= mCacheDir
;
411 llvm::sys::path::append(filePath
, moduleID
);
414 llvm::raw_fd_ostream
fileObj(filePath
.c_str(), err
, llvm::sys::fs::F_None
);
416 uint32_t objcrc
= ComputeCRC(0, Obj
.getBufferStart(), Obj
.getBufferSize());
418 JitCacheFileHeader header
;
419 header
.Init(mCurrentModuleCRC
, objcrc
, moduleID
, mCpu
, Obj
.getBufferSize());
421 fileObj
.write((const char*)&header
, sizeof(header
));
422 fileObj
<< Obj
.getBuffer();
426 /// Returns a pointer to a newly allocated MemoryBuffer that contains the
427 /// object which corresponds with Module M, or 0 if an object is not
429 std::unique_ptr
<llvm::MemoryBuffer
> JitCache::getObject(const llvm::Module
* M
)
431 const std::string
& moduleID
= M
->getModuleIdentifier();
432 mCurrentModuleCRC
= ComputeModuleCRC(M
);
434 if (!moduleID
.length())
439 if (!llvm::sys::fs::exists(mCacheDir
))
444 llvm::SmallString
<MAX_PATH
> filePath
= mCacheDir
;
445 llvm::sys::path::append(filePath
, moduleID
);
447 FILE* fpIn
= fopen(filePath
.c_str(), "rb");
453 std::unique_ptr
<llvm::MemoryBuffer
> pBuf
= nullptr;
456 JitCacheFileHeader header
;
457 if (!fread(&header
, sizeof(header
), 1, fpIn
))
462 if (!header
.IsValid(mCurrentModuleCRC
, moduleID
, mCpu
))
467 #if LLVM_VERSION_MAJOR < 6
468 pBuf
= llvm::MemoryBuffer::getNewUninitMemBuffer(size_t(header
.GetBufferSize()));
470 pBuf
= llvm::WritableMemoryBuffer::getNewUninitMemBuffer(size_t(header
.GetBufferSize()));
472 if (!fread(const_cast<char*>(pBuf
->getBufferStart()), header
.GetBufferSize(), 1, fpIn
))
478 if (header
.GetBufferCRC() != ComputeCRC(0, pBuf
->getBufferStart(), pBuf
->getBufferSize()))
480 SWR_TRACE("Invalid object cache file, ignoring: %s", filePath
.c_str());