swr/rast: Fix one more invalid object format for windows.
[mesa.git] / src / gallium / drivers / swr / rasterizer / jitter / JitManager.cpp
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 mpExec = EngineBuilder(std::move(newModule))
100 .setTargetOptions(tOpts)
101 .setOptLevel(CodeGenOpt::Aggressive)
102 .setMCPU(hostCPUName)
103 .create();
104
105 if (KNOB_JIT_ENABLE_CACHE)
106 {
107 mCache.SetCpu(hostCPUName);
108 mpExec->setObjectCache(&mCache);
109 }
110
111 #if LLVM_USE_INTEL_JITEVENTS
112 JITEventListener *vTune = JITEventListener::createIntelJITEventListener();
113 mpExec->RegisterJITEventListener(vTune);
114 #endif
115
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
120
121 // fetch function signature
122 #if USE_SIMD16_SHADERS
123 // typedef void(__cdecl *PFN_FETCH_FUNC)(SWR_FETCH_CONTEXT& fetchInfo, simd16vertex& out);
124 #else
125 // typedef void(__cdecl *PFN_FETCH_FUNC)(SWR_FETCH_CONTEXT& fetchInfo, simdvertex& out);
126 #endif
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));
131 #else
132 fsArgs.push_back(PointerType::get(Gen_simdvertex(this), 0));
133 #endif
134
135 mFetchShaderTy = FunctionType::get(Type::getVoidTy(mContext), fsArgs, false);
136
137 mSimtFP32Ty = VectorType::get(mFP32Ty, mVWidth);
138 mSimtInt32Ty = VectorType::get(mInt32Ty, mVWidth);
139
140 mSimdVectorTy = ArrayType::get(mSimtFP32Ty, 4);
141 mSimdVectorInt32Ty = ArrayType::get(mSimtInt32Ty, 4);
142
143 #if USE_SIMD16_SHADERS
144 mSimd16FP32Ty = ArrayType::get(mSimtFP32Ty, 2);
145 mSimd16Int32Ty = ArrayType::get(mSimtInt32Ty, 2);
146
147 mSimd16VectorFP32Ty = ArrayType::get(mSimd16FP32Ty, 4);
148 mSimd16VectorInt32Ty = ArrayType::get(mSimd16Int32Ty, 4);
149
150 #endif
151 #if defined(_WIN32)
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);
158 #endif
159
160 #if defined(_WIN32)
161 if (KNOB_DUMP_SHADER_IR)
162 {
163 CreateDirectoryPath(INTEL_OUTPUT_DIR);
164 CreateDirectoryPath(SWR_OUTPUT_DIR);
165 CreateDirectoryPath(JITTER_OUTPUT_DIR);
166 }
167 #endif
168 }
169
170 //////////////////////////////////////////////////////////////////////////
171 /// @brief Create new LLVM module.
172 void JitManager::SetupNewModule()
173 {
174 SWR_ASSERT(mIsModuleFinalized == true && "Current module is not finalized!");
175
176 std::unique_ptr<Module> newModule(new Module("", mContext));
177 mpCurrentModule = newModule.get();
178 #if defined(_WIN32)
179 // Needed for MCJIT on windows
180 Triple hostTriple(sys::getProcessTriple());
181 hostTriple.setObjectFormat(Triple::COFF);
182 newModule->setTargetTriple(hostTriple.getTriple());
183 #endif // _WIN32
184
185 mpExec->addModule(std::move(newModule));
186 mIsModuleFinalized = false;
187 }
188
189
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)
195 {
196 if (KNOB_DUMP_SHADER_IR)
197 {
198
199 #if defined(_WIN32)
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());
207 #endif
208
209 std::error_code EC;
210 Module* pModule = pFunction->getParent();
211 const char *funcName = pFunction->getName().data();
212 char fName[256];
213 #if defined(_WIN32)
214 sprintf(fName, "%s\\%s.%s.asm", outDir.str().c_str(), funcName, fileName);
215 #else
216 sprintf(fName, "%s.%s.asm", funcName, fileName);
217 #endif
218
219 raw_fd_ostream filestream(fName, EC, llvm::sys::fs::F_None);
220
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);
226 delete pMPasses;
227 pTarget->Options.MCOptions.AsmVerbose = false;
228 }
229 }
230
231 //////////////////////////////////////////////////////////////////////////
232 /// @brief Dump function to file.
233 void JitManager::DumpToFile(Function *f, const char *fileName)
234 {
235 if (KNOB_DUMP_SHADER_IR)
236 {
237 #if defined(_WIN32)
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());
245 #endif
246
247 std::error_code EC;
248 const char *funcName = f->getName().data();
249 char fName[256];
250 #if defined(_WIN32)
251 sprintf(fName, "%s\\%s.%s.ll", outDir.str().c_str(), funcName, fileName);
252 #else
253 sprintf(fName, "%s.%s.ll", funcName, fileName);
254 #endif
255 raw_fd_ostream fd(fName, EC, llvm::sys::fs::F_None);
256 Module* pModule = f->getParent();
257 pModule->print(fd, nullptr);
258
259 #if defined(_WIN32)
260 sprintf(fName, "%s\\cfg.%s.%s.dot", outDir.str().c_str(), funcName, fileName);
261 #else
262 sprintf(fName, "cfg.%s.%s.dot", funcName, fileName);
263 #endif
264 fd.flush();
265
266 raw_fd_ostream fd_cfg(fName, EC, llvm::sys::fs::F_Text);
267 WriteGraph(fd_cfg, (const Function*)f);
268
269 fd_cfg.flush();
270 }
271 }
272
273 extern "C"
274 {
275 bool g_DllActive = true;
276
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)
281 {
282 return new JitManager(targetSimdWidth, arch, core);
283 }
284
285 //////////////////////////////////////////////////////////////////////////
286 /// @brief Destroy JIT context.
287 void JITCALL JitDestroyContext(HANDLE hJitContext)
288 {
289 if (g_DllActive)
290 {
291 delete reinterpret_cast<JitManager*>(hJitContext);
292 }
293 }
294 }
295
296 //////////////////////////////////////////////////////////////////////////
297 /// JitCache
298 //////////////////////////////////////////////////////////////////////////
299
300 //////////////////////////////////////////////////////////////////////////
301 /// JitCacheFileHeader
302 //////////////////////////////////////////////////////////////////////////
303 struct JitCacheFileHeader
304 {
305 void Init(uint32_t llCRC, uint32_t objCRC, const std::string& moduleID, const std::string& cpu, uint64_t bufferSize)
306 {
307 m_MagicNumber = JC_MAGIC_NUMBER;
308 m_BufferSize = bufferSize;
309 m_llCRC = llCRC;
310 m_platformKey = JC_PLATFORM_KEY;
311 m_objCRC = objCRC;
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;
316 }
317
318 bool IsValid(uint32_t llCRC, const std::string& moduleID, const std::string& cpu)
319 {
320 if ((m_MagicNumber != JC_MAGIC_NUMBER) ||
321 (m_llCRC != llCRC) ||
322 (m_platformKey != JC_PLATFORM_KEY))
323 {
324 return false;
325 }
326
327 m_ModuleID[JC_STR_MAX_LEN - 1] = 0;
328 if (strncmp(moduleID.c_str(), m_ModuleID, JC_STR_MAX_LEN - 1))
329 {
330 return false;
331 }
332
333 m_Cpu[JC_STR_MAX_LEN - 1] = 0;
334 if (strncmp(cpu.c_str(), m_Cpu, JC_STR_MAX_LEN - 1))
335 {
336 return false;
337 }
338
339 return true;
340 }
341
342 uint64_t GetBufferSize() const { return m_BufferSize; }
343 uint64_t GetBufferCRC() const { return m_objCRC; }
344
345 private:
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);
353
354 uint64_t m_MagicNumber;
355 uint64_t m_BufferSize;
356 uint32_t m_llCRC;
357 uint32_t m_platformKey;
358 uint32_t m_objCRC;
359 char m_ModuleID[JC_STR_MAX_LEN];
360 char m_Cpu[JC_STR_MAX_LEN];
361 };
362
363 static inline uint32_t ComputeModuleCRC(const llvm::Module* M)
364 {
365 std::string bitcodeBuffer;
366 raw_string_ostream bitcodeStream(bitcodeBuffer);
367
368 llvm::WriteBitcodeToFile(M, bitcodeStream);
369 //M->print(bitcodeStream, nullptr, false);
370
371 bitcodeStream.flush();
372
373 return ComputeCRC(0, bitcodeBuffer.data(), bitcodeBuffer.size());
374 }
375
376 /// constructor
377 JitCache::JitCache()
378 {
379 #if defined(__APPLE) || defined(FORCE_LINUX) || defined(__linux__) || defined(__gnu_linux__)
380 if (strncmp(KNOB_JIT_CACHE_DIR.c_str(), "~/", 2) == 0) {
381 char *homedir;
382 if (!(homedir = getenv("HOME"))) {
383 homedir = getpwuid(getuid())->pw_dir;
384 }
385 mCacheDir = homedir;
386 mCacheDir += (KNOB_JIT_CACHE_DIR.c_str() + 1);
387 } else
388 #endif
389 {
390 mCacheDir = KNOB_JIT_CACHE_DIR;
391 }
392 }
393
394 /// notifyObjectCompiled - Provides a pointer to compiled code for Module M.
395 void JitCache::notifyObjectCompiled(const llvm::Module *M, llvm::MemoryBufferRef Obj)
396 {
397 const std::string& moduleID = M->getModuleIdentifier();
398 if (!moduleID.length())
399 {
400 return;
401 }
402
403 if (!llvm::sys::fs::exists(mCacheDir.str()) &&
404 llvm::sys::fs::create_directories(mCacheDir.str()))
405 {
406 SWR_INVALID("Unable to create directory: %s", mCacheDir.c_str());
407 return;
408 }
409
410 llvm::SmallString<MAX_PATH> filePath = mCacheDir;
411 llvm::sys::path::append(filePath, moduleID);
412
413 std::error_code err;
414 llvm::raw_fd_ostream fileObj(filePath.c_str(), err, llvm::sys::fs::F_None);
415
416 uint32_t objcrc = ComputeCRC(0, Obj.getBufferStart(), Obj.getBufferSize());
417
418 JitCacheFileHeader header;
419 header.Init(mCurrentModuleCRC, objcrc, moduleID, mCpu, Obj.getBufferSize());
420
421 fileObj.write((const char*)&header, sizeof(header));
422 fileObj << Obj.getBuffer();
423 fileObj.flush();
424 }
425
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
428 /// available.
429 std::unique_ptr<llvm::MemoryBuffer> JitCache::getObject(const llvm::Module* M)
430 {
431 const std::string& moduleID = M->getModuleIdentifier();
432 mCurrentModuleCRC = ComputeModuleCRC(M);
433
434 if (!moduleID.length())
435 {
436 return nullptr;
437 }
438
439 if (!llvm::sys::fs::exists(mCacheDir))
440 {
441 return nullptr;
442 }
443
444 llvm::SmallString<MAX_PATH> filePath = mCacheDir;
445 llvm::sys::path::append(filePath, moduleID);
446
447 FILE* fpIn = fopen(filePath.c_str(), "rb");
448 if (!fpIn)
449 {
450 return nullptr;
451 }
452
453 std::unique_ptr<llvm::MemoryBuffer> pBuf = nullptr;
454 do
455 {
456 JitCacheFileHeader header;
457 if (!fread(&header, sizeof(header), 1, fpIn))
458 {
459 break;
460 }
461
462 if (!header.IsValid(mCurrentModuleCRC, moduleID, mCpu))
463 {
464 break;
465 }
466
467 #if LLVM_VERSION_MAJOR < 6
468 pBuf = llvm::MemoryBuffer::getNewUninitMemBuffer(size_t(header.GetBufferSize()));
469 #else
470 pBuf = llvm::WritableMemoryBuffer::getNewUninitMemBuffer(size_t(header.GetBufferSize()));
471 #endif
472 if (!fread(const_cast<char*>(pBuf->getBufferStart()), header.GetBufferSize(), 1, fpIn))
473 {
474 pBuf = nullptr;
475 break;
476 }
477
478 if (header.GetBufferCRC() != ComputeCRC(0, pBuf->getBufferStart(), pBuf->getBufferSize()))
479 {
480 SWR_TRACE("Invalid object cache file, ignoring: %s", filePath.c_str());
481 pBuf = nullptr;
482 break;
483 }
484 } while (0);
485
486 fclose(fpIn);
487
488 return pBuf;
489 }