swr: [rasterizer jitter] adjust jitmanager assert
[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 #if defined(_WIN32)
31 #pragma warning(disable: 4800 4146 4244 4267 4355 4996)
32 #endif
33
34 #include "jit_api.h"
35 #include "JitManager.h"
36 #include "fetch_jit.h"
37
38 #pragma push_macro("DEBUG")
39 #undef DEBUG
40
41 #if defined(_WIN32)
42 #include "llvm/ADT/Triple.h"
43 #endif
44 #include "llvm/IR/Function.h"
45
46 #include "llvm/Support/MemoryBuffer.h"
47 #include "llvm/Support/SourceMgr.h"
48
49 #include "llvm/Analysis/CFGPrinter.h"
50 #include "llvm/IRReader/IRReader.h"
51 #include "llvm/Target/TargetMachine.h"
52 #include "llvm/Support/FormattedStream.h"
53
54 #if LLVM_USE_INTEL_JITEVENTS
55 #include "llvm/ExecutionEngine/JITEventListener.h"
56 #endif
57
58 #pragma pop_macro("DEBUG")
59
60 #include "core/state.h"
61
62 #include "state_llvm.h"
63
64 #include <sstream>
65 #if defined(_WIN32)
66 #include <psapi.h>
67 #include <cstring>
68
69 #define INTEL_OUTPUT_DIR "c:\\Intel"
70 #define SWR_OUTPUT_DIR INTEL_OUTPUT_DIR "\\SWR"
71 #define JITTER_OUTPUT_DIR SWR_OUTPUT_DIR "\\Jitter"
72 #endif
73
74 using namespace llvm;
75 using namespace SwrJit;
76
77 //////////////////////////////////////////////////////////////////////////
78 /// @brief Contructor for JitManager.
79 /// @param simdWidth - SIMD width to be used in generated program.
80 JitManager::JitManager(uint32_t simdWidth, const char *arch, const char* core)
81 : mContext(), mBuilder(mContext), mIsModuleFinalized(true), mJitNumber(0), mVWidth(simdWidth), mArch(arch)
82 {
83 InitializeNativeTarget();
84 InitializeNativeTargetAsmPrinter();
85 InitializeNativeTargetDisassembler();
86
87 TargetOptions tOpts;
88 tOpts.AllowFPOpFusion = FPOpFusion::Fast;
89 tOpts.NoInfsFPMath = false;
90 tOpts.NoNaNsFPMath = false;
91 tOpts.UnsafeFPMath = true;
92 #if defined(_DEBUG)
93 #if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7
94 tOpts.NoFramePointerElim = true;
95 #endif
96 #endif
97
98 //tOpts.PrintMachineCode = true;
99
100 mCore = std::string(core);
101 std::transform(mCore.begin(), mCore.end(), mCore.begin(), ::tolower);
102
103 std::stringstream fnName("JitModule", std::ios_base::in | std::ios_base::out | std::ios_base::ate);
104 fnName << mJitNumber++;
105 std::unique_ptr<Module> newModule(new Module(fnName.str(), mContext));
106 mpCurrentModule = newModule.get();
107
108 auto &&EB = EngineBuilder(std::move(newModule));
109 EB.setTargetOptions(tOpts);
110 EB.setOptLevel(CodeGenOpt::Aggressive);
111
112 StringRef hostCPUName;
113
114 // force JIT to use the same CPU arch as the rest of swr
115 if(mArch.AVX512F())
116 {
117 assert(0 && "Implement AVX512 jitter");
118 hostCPUName = sys::getHostCPUName();
119 if (mVWidth == 0)
120 {
121 mVWidth = 16;
122 }
123 }
124 else if(mArch.AVX2())
125 {
126 hostCPUName = StringRef("core-avx2");
127 if (mVWidth == 0)
128 {
129 mVWidth = 8;
130 }
131 }
132 else if(mArch.AVX())
133 {
134 if (mArch.F16C())
135 {
136 hostCPUName = StringRef("core-avx-i");
137 }
138 else
139 {
140 hostCPUName = StringRef("corei7-avx");
141 }
142 if (mVWidth == 0)
143 {
144 mVWidth = 8;
145 }
146 }
147 else
148 {
149 hostCPUName = sys::getHostCPUName();
150 if (mVWidth == 0)
151 {
152 mVWidth = 8; // 4?
153 }
154 }
155
156 EB.setMCPU(hostCPUName);
157
158 #if defined(_WIN32)
159 // Needed for MCJIT on windows
160 Triple hostTriple(sys::getProcessTriple());
161 hostTriple.setObjectFormat(Triple::ELF);
162 mpCurrentModule->setTargetTriple(hostTriple.getTriple());
163 #endif // _WIN32
164
165 mpExec = EB.create();
166
167 #if LLVM_USE_INTEL_JITEVENTS
168 JITEventListener *vTune = JITEventListener::createIntelJITEventListener();
169 mpExec->RegisterJITEventListener(vTune);
170 #endif
171
172 mFP32Ty = Type::getFloatTy(mContext); // float type
173 mInt8Ty = Type::getInt8Ty(mContext);
174 mInt32Ty = Type::getInt32Ty(mContext); // int type
175 mInt64Ty = Type::getInt64Ty(mContext); // int type
176 mV4FP32Ty = StructType::get(mContext, std::vector<Type*>(4, mFP32Ty), false); // vector4 float type (represented as structure)
177 mV4Int32Ty = StructType::get(mContext, std::vector<Type*>(4, mInt32Ty), false); // vector4 int type
178
179 // fetch function signature
180 // typedef void(__cdecl *PFN_FETCH_FUNC)(SWR_FETCH_CONTEXT& fetchInfo, simdvertex& out);
181 std::vector<Type*> fsArgs;
182 fsArgs.push_back(PointerType::get(Gen_SWR_FETCH_CONTEXT(this), 0));
183 fsArgs.push_back(PointerType::get(Gen_simdvertex(this), 0));
184
185 mFetchShaderTy = FunctionType::get(Type::getVoidTy(mContext), fsArgs, false);
186
187 mSimtFP32Ty = VectorType::get(mFP32Ty, mVWidth);
188 mSimtInt32Ty = VectorType::get(mInt32Ty, mVWidth);
189
190 mSimdVectorTy = StructType::get(mContext, std::vector<Type*>(4, mSimtFP32Ty), false);
191 mSimdVectorInt32Ty = StructType::get(mContext, std::vector<Type*>(4, mSimtInt32Ty), false);
192
193 #if defined(_WIN32)
194 // explicitly instantiate used symbols from potentially staticly linked libs
195 sys::DynamicLibrary::AddSymbol("exp2f", &exp2f);
196 sys::DynamicLibrary::AddSymbol("log2f", &log2f);
197 sys::DynamicLibrary::AddSymbol("sinf", &sinf);
198 sys::DynamicLibrary::AddSymbol("cosf", &cosf);
199 sys::DynamicLibrary::AddSymbol("powf", &powf);
200 #endif
201
202 #if defined(_WIN32)
203 if (KNOB_DUMP_SHADER_IR)
204 {
205 CreateDirectory(INTEL_OUTPUT_DIR, NULL);
206 CreateDirectory(SWR_OUTPUT_DIR, NULL);
207 CreateDirectory(JITTER_OUTPUT_DIR, NULL);
208 }
209 #endif
210 }
211
212 //////////////////////////////////////////////////////////////////////////
213 /// @brief Create new LLVM module.
214 void JitManager::SetupNewModule()
215 {
216 SWR_ASSERT(mIsModuleFinalized == true && "Current module is not finalized!");
217
218 std::stringstream fnName("JitModule", std::ios_base::in | std::ios_base::out | std::ios_base::ate);
219 fnName << mJitNumber++;
220 std::unique_ptr<Module> newModule(new Module(fnName.str(), mContext));
221 mpCurrentModule = newModule.get();
222 #if defined(_WIN32)
223 // Needed for MCJIT on windows
224 Triple hostTriple(sys::getProcessTriple());
225 hostTriple.setObjectFormat(Triple::ELF);
226 newModule->setTargetTriple(hostTriple.getTriple());
227 #endif // _WIN32
228
229 mpExec->addModule(std::move(newModule));
230 mIsModuleFinalized = false;
231 }
232
233 //////////////////////////////////////////////////////////////////////////
234 /// @brief Create new LLVM module from IR.
235 bool JitManager::SetupModuleFromIR(const uint8_t *pIR)
236 {
237 std::unique_ptr<MemoryBuffer> pMem = MemoryBuffer::getMemBuffer(StringRef((const char*)pIR), "");
238
239 SMDiagnostic Err;
240 std::unique_ptr<Module> newModule = parseIR(pMem.get()->getMemBufferRef(), Err, mContext);
241
242 SWR_REL_ASSERT(
243 !(newModule == nullptr),
244 "Parse failed!\n"
245 "%s", Err.getMessage().data());
246 if (newModule == nullptr)
247 {
248 return false;
249 }
250
251 #if HAVE_LLVM == 0x307
252 // llvm-3.7 has mismatched setDataLyout/getDataLayout APIs
253 newModule->setDataLayout(*mpExec->getDataLayout());
254 #else
255 newModule->setDataLayout(mpExec->getDataLayout());
256 #endif
257
258 mpCurrentModule = newModule.get();
259 #if defined(_WIN32)
260 // Needed for MCJIT on windows
261 Triple hostTriple(sys::getProcessTriple());
262 hostTriple.setObjectFormat(Triple::ELF);
263 newModule->setTargetTriple(hostTriple.getTriple());
264 #endif // _WIN32
265
266 mpExec->addModule(std::move(newModule));
267 mIsModuleFinalized = false;
268
269 return true;
270 }
271
272 //////////////////////////////////////////////////////////////////////////
273 /// @brief Dump function x86 assembly to file.
274 /// @note This should only be called after the module has been jitted to x86 and the
275 /// module will not be further accessed.
276 void JitManager::DumpAsm(Function* pFunction, const char* fileName)
277 {
278 if (KNOB_DUMP_SHADER_IR)
279 {
280
281 #if defined(_WIN32)
282 DWORD pid = GetCurrentProcessId();
283 TCHAR procname[MAX_PATH];
284 GetModuleFileName(NULL, procname, MAX_PATH);
285 const char* pBaseName = strrchr(procname, '\\');
286 std::stringstream outDir;
287 outDir << JITTER_OUTPUT_DIR << pBaseName << "_" << pid << std::ends;
288 CreateDirectory(outDir.str().c_str(), NULL);
289 #endif
290
291 std::error_code EC;
292 Module* pModule = pFunction->getParent();
293 const char *funcName = pFunction->getName().data();
294 char fName[256];
295 #if defined(_WIN32)
296 sprintf(fName, "%s\\%s.%s.asm", outDir.str().c_str(), funcName, fileName);
297 #else
298 sprintf(fName, "%s.%s.asm", funcName, fileName);
299 #endif
300
301 #if HAVE_LLVM == 0x306
302 raw_fd_ostream fd(fName, EC, llvm::sys::fs::F_None);
303 formatted_raw_ostream filestream(fd);
304 #else
305 raw_fd_ostream filestream(fName, EC, llvm::sys::fs::F_None);
306 #endif
307
308 legacy::PassManager* pMPasses = new legacy::PassManager();
309 auto* pTarget = mpExec->getTargetMachine();
310 pTarget->Options.MCOptions.AsmVerbose = true;
311 pTarget->addPassesToEmitFile(*pMPasses, filestream, TargetMachine::CGFT_AssemblyFile);
312 pMPasses->run(*pModule);
313 delete pMPasses;
314 pTarget->Options.MCOptions.AsmVerbose = false;
315 }
316 }
317
318 //////////////////////////////////////////////////////////////////////////
319 /// @brief Dump function to file.
320 void JitManager::DumpToFile(Function *f, const char *fileName)
321 {
322 if (KNOB_DUMP_SHADER_IR)
323 {
324 #if defined(_WIN32)
325 DWORD pid = GetCurrentProcessId();
326 TCHAR procname[MAX_PATH];
327 GetModuleFileName(NULL, procname, MAX_PATH);
328 const char* pBaseName = strrchr(procname, '\\');
329 std::stringstream outDir;
330 outDir << JITTER_OUTPUT_DIR << pBaseName << "_" << pid << std::ends;
331 CreateDirectory(outDir.str().c_str(), NULL);
332 #endif
333
334 std::error_code EC;
335 const char *funcName = f->getName().data();
336 char fName[256];
337 #if defined(_WIN32)
338 sprintf(fName, "%s\\%s.%s.ll", outDir.str().c_str(), funcName, fileName);
339 #else
340 sprintf(fName, "%s.%s.ll", funcName, fileName);
341 #endif
342 raw_fd_ostream fd(fName, EC, llvm::sys::fs::F_None);
343 Module* pModule = f->getParent();
344 pModule->print(fd, nullptr);
345
346 #if defined(_WIN32)
347 sprintf(fName, "%s\\cfg.%s.%s.dot", outDir.str().c_str(), funcName, fileName);
348 #else
349 sprintf(fName, "cfg.%s.%s.dot", funcName, fileName);
350 #endif
351 fd.flush();
352
353 raw_fd_ostream fd_cfg(fName, EC, llvm::sys::fs::F_Text);
354 WriteGraph(fd_cfg, (const Function*)f);
355
356 fd_cfg.flush();
357 }
358 }
359
360 extern "C"
361 {
362 bool g_DllActive = true;
363
364 //////////////////////////////////////////////////////////////////////////
365 /// @brief Create JIT context.
366 /// @param simdWidth - SIMD width to be used in generated program.
367 HANDLE JITCALL JitCreateContext(uint32_t targetSimdWidth, const char* arch, const char* core)
368 {
369 return new JitManager(targetSimdWidth, arch, core);
370 }
371
372 //////////////////////////////////////////////////////////////////////////
373 /// @brief Destroy JIT context.
374 void JITCALL JitDestroyContext(HANDLE hJitContext)
375 {
376 if (g_DllActive)
377 {
378 delete reinterpret_cast<JitManager*>(hJitContext);
379 }
380 }
381 }