5bd21a1cf025a14c5f7e0cc536fcb76939ee8965
[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 #pragma push_macro("DEBUG")
35 #undef DEBUG
36
37 #if defined(_WIN32)
38 #include "llvm/ADT/Triple.h"
39 #endif
40 #include "llvm/IR/Function.h"
41
42 #include "llvm/Support/MemoryBuffer.h"
43 #include "llvm/Support/SourceMgr.h"
44
45 #include "llvm/Analysis/CFGPrinter.h"
46 #include "llvm/IRReader/IRReader.h"
47 #include "llvm/Target/TargetMachine.h"
48 #include "llvm/Support/FormattedStream.h"
49
50 #if LLVM_USE_INTEL_JITEVENTS
51 #include "llvm/ExecutionEngine/JITEventListener.h"
52 #endif
53
54 #pragma pop_macro("DEBUG")
55
56 #include "JitManager.h"
57 #include "jit_api.h"
58 #include "fetch_jit.h"
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 = false;
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 hostCPUName = sys::getHostCPUName();
115
116 EB.setMCPU(hostCPUName);
117
118 #if defined(_WIN32)
119 // Needed for MCJIT on windows
120 Triple hostTriple(sys::getProcessTriple());
121 hostTriple.setObjectFormat(Triple::ELF);
122 mpCurrentModule->setTargetTriple(hostTriple.getTriple());
123 #endif // _WIN32
124
125 mpExec = EB.create();
126
127 #if LLVM_USE_INTEL_JITEVENTS
128 JITEventListener *vTune = JITEventListener::createIntelJITEventListener();
129 mpExec->RegisterJITEventListener(vTune);
130 #endif
131
132 mFP32Ty = Type::getFloatTy(mContext); // float type
133 mInt8Ty = Type::getInt8Ty(mContext);
134 mInt32Ty = Type::getInt32Ty(mContext); // int type
135 mInt64Ty = Type::getInt64Ty(mContext); // int type
136
137 // fetch function signature
138 // typedef void(__cdecl *PFN_FETCH_FUNC)(SWR_FETCH_CONTEXT& fetchInfo, simdvertex& out);
139 std::vector<Type*> fsArgs;
140 fsArgs.push_back(PointerType::get(Gen_SWR_FETCH_CONTEXT(this), 0));
141 fsArgs.push_back(PointerType::get(Gen_simdvertex(this), 0));
142
143 mFetchShaderTy = FunctionType::get(Type::getVoidTy(mContext), fsArgs, false);
144
145 mSimtFP32Ty = VectorType::get(mFP32Ty, mVWidth);
146 mSimtInt32Ty = VectorType::get(mInt32Ty, mVWidth);
147
148 mSimdVectorTy = ArrayType::get(mSimtFP32Ty, 4);
149 mSimdVectorInt32Ty = ArrayType::get(mSimtInt32Ty, 4);
150
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 CreateDirectory(INTEL_OUTPUT_DIR, NULL);
164 CreateDirectory(SWR_OUTPUT_DIR, NULL);
165 CreateDirectory(JITTER_OUTPUT_DIR, NULL);
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::stringstream fnName("JitModule", std::ios_base::in | std::ios_base::out | std::ios_base::ate);
177 fnName << mJitNumber++;
178 std::unique_ptr<Module> newModule(new Module(fnName.str(), mContext));
179 mpCurrentModule = newModule.get();
180 #if defined(_WIN32)
181 // Needed for MCJIT on windows
182 Triple hostTriple(sys::getProcessTriple());
183 hostTriple.setObjectFormat(Triple::ELF);
184 newModule->setTargetTriple(hostTriple.getTriple());
185 #endif // _WIN32
186
187 mpExec->addModule(std::move(newModule));
188 mIsModuleFinalized = false;
189 }
190
191 //////////////////////////////////////////////////////////////////////////
192 /// @brief Create new LLVM module from IR.
193 bool JitManager::SetupModuleFromIR(const uint8_t *pIR)
194 {
195 std::unique_ptr<MemoryBuffer> pMem = MemoryBuffer::getMemBuffer(StringRef((const char*)pIR), "");
196
197 SMDiagnostic Err;
198 std::unique_ptr<Module> newModule = parseIR(pMem.get()->getMemBufferRef(), Err, mContext);
199
200 SWR_REL_ASSERT(
201 !(newModule == nullptr),
202 "Parse failed!\n"
203 "%s", Err.getMessage().data());
204 if (newModule == nullptr)
205 {
206 return false;
207 }
208
209 #if HAVE_LLVM == 0x307
210 // llvm-3.7 has mismatched setDataLyout/getDataLayout APIs
211 newModule->setDataLayout(*mpExec->getDataLayout());
212 #else
213 newModule->setDataLayout(mpExec->getDataLayout());
214 #endif
215
216 mpCurrentModule = newModule.get();
217 #if defined(_WIN32)
218 // Needed for MCJIT on windows
219 Triple hostTriple(sys::getProcessTriple());
220 hostTriple.setObjectFormat(Triple::ELF);
221 newModule->setTargetTriple(hostTriple.getTriple());
222 #endif // _WIN32
223
224 mpExec->addModule(std::move(newModule));
225 mIsModuleFinalized = false;
226
227 return true;
228 }
229
230 //////////////////////////////////////////////////////////////////////////
231 /// @brief Dump function x86 assembly to file.
232 /// @note This should only be called after the module has been jitted to x86 and the
233 /// module will not be further accessed.
234 void JitManager::DumpAsm(Function* pFunction, const char* fileName)
235 {
236 if (KNOB_DUMP_SHADER_IR)
237 {
238
239 #if defined(_WIN32)
240 DWORD pid = GetCurrentProcessId();
241 TCHAR procname[MAX_PATH];
242 GetModuleFileName(NULL, procname, MAX_PATH);
243 const char* pBaseName = strrchr(procname, '\\');
244 std::stringstream outDir;
245 outDir << JITTER_OUTPUT_DIR << pBaseName << "_" << pid << std::ends;
246 CreateDirectory(outDir.str().c_str(), NULL);
247 #endif
248
249 std::error_code EC;
250 Module* pModule = pFunction->getParent();
251 const char *funcName = pFunction->getName().data();
252 char fName[256];
253 #if defined(_WIN32)
254 sprintf(fName, "%s\\%s.%s.asm", outDir.str().c_str(), funcName, fileName);
255 #else
256 sprintf(fName, "%s.%s.asm", funcName, fileName);
257 #endif
258
259 #if HAVE_LLVM == 0x306
260 raw_fd_ostream fd(fName, EC, llvm::sys::fs::F_None);
261 formatted_raw_ostream filestream(fd);
262 #else
263 raw_fd_ostream filestream(fName, EC, llvm::sys::fs::F_None);
264 #endif
265
266 legacy::PassManager* pMPasses = new legacy::PassManager();
267 auto* pTarget = mpExec->getTargetMachine();
268 pTarget->Options.MCOptions.AsmVerbose = true;
269 pTarget->addPassesToEmitFile(*pMPasses, filestream, TargetMachine::CGFT_AssemblyFile);
270 pMPasses->run(*pModule);
271 delete pMPasses;
272 pTarget->Options.MCOptions.AsmVerbose = false;
273 }
274 }
275
276 //////////////////////////////////////////////////////////////////////////
277 /// @brief Dump function to file.
278 void JitManager::DumpToFile(Function *f, const char *fileName)
279 {
280 if (KNOB_DUMP_SHADER_IR)
281 {
282 #if defined(_WIN32)
283 DWORD pid = GetCurrentProcessId();
284 TCHAR procname[MAX_PATH];
285 GetModuleFileName(NULL, procname, MAX_PATH);
286 const char* pBaseName = strrchr(procname, '\\');
287 std::stringstream outDir;
288 outDir << JITTER_OUTPUT_DIR << pBaseName << "_" << pid << std::ends;
289 CreateDirectory(outDir.str().c_str(), NULL);
290 #endif
291
292 std::error_code EC;
293 const char *funcName = f->getName().data();
294 char fName[256];
295 #if defined(_WIN32)
296 sprintf(fName, "%s\\%s.%s.ll", outDir.str().c_str(), funcName, fileName);
297 #else
298 sprintf(fName, "%s.%s.ll", funcName, fileName);
299 #endif
300 raw_fd_ostream fd(fName, EC, llvm::sys::fs::F_None);
301 Module* pModule = f->getParent();
302 pModule->print(fd, nullptr);
303
304 #if defined(_WIN32)
305 sprintf(fName, "%s\\cfg.%s.%s.dot", outDir.str().c_str(), funcName, fileName);
306 #else
307 sprintf(fName, "cfg.%s.%s.dot", funcName, fileName);
308 #endif
309 fd.flush();
310
311 raw_fd_ostream fd_cfg(fName, EC, llvm::sys::fs::F_Text);
312 WriteGraph(fd_cfg, (const Function*)f);
313
314 fd_cfg.flush();
315 }
316 }
317
318 extern "C"
319 {
320 bool g_DllActive = true;
321
322 //////////////////////////////////////////////////////////////////////////
323 /// @brief Create JIT context.
324 /// @param simdWidth - SIMD width to be used in generated program.
325 HANDLE JITCALL JitCreateContext(uint32_t targetSimdWidth, const char* arch, const char* core)
326 {
327 return new JitManager(targetSimdWidth, arch, core);
328 }
329
330 //////////////////////////////////////////////////////////////////////////
331 /// @brief Destroy JIT context.
332 void JITCALL JitDestroyContext(HANDLE hJitContext)
333 {
334 if (g_DllActive)
335 {
336 delete reinterpret_cast<JitManager*>(hJitContext);
337 }
338 }
339 }