• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
JitManager(uint32_t simdWidth,const char * arch,const char * core)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     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     mV4FP32Ty = StructType::get(mContext, std::vector<Type*>(4, mFP32Ty), false); // vector4 float type (represented as structure)
137     mV4Int32Ty = StructType::get(mContext, std::vector<Type*>(4, mInt32Ty), false); // vector4 int type
138 
139     // fetch function signature
140     // typedef void(__cdecl *PFN_FETCH_FUNC)(SWR_FETCH_CONTEXT& fetchInfo, simdvertex& out);
141     std::vector<Type*> fsArgs;
142     fsArgs.push_back(PointerType::get(Gen_SWR_FETCH_CONTEXT(this), 0));
143     fsArgs.push_back(PointerType::get(Gen_simdvertex(this), 0));
144 
145     mFetchShaderTy = FunctionType::get(Type::getVoidTy(mContext), fsArgs, false);
146 
147     mSimtFP32Ty = VectorType::get(mFP32Ty, mVWidth);
148     mSimtInt32Ty = VectorType::get(mInt32Ty, mVWidth);
149 
150     mSimdVectorTy = StructType::get(mContext, std::vector<Type*>(4, mSimtFP32Ty), false);
151     mSimdVectorInt32Ty = StructType::get(mContext, std::vector<Type*>(4, mSimtInt32Ty), false);
152 
153 #if defined(_WIN32)
154     // explicitly instantiate used symbols from potentially staticly linked libs
155     sys::DynamicLibrary::AddSymbol("exp2f", &exp2f);
156     sys::DynamicLibrary::AddSymbol("log2f", &log2f);
157     sys::DynamicLibrary::AddSymbol("sinf", &sinf);
158     sys::DynamicLibrary::AddSymbol("cosf", &cosf);
159     sys::DynamicLibrary::AddSymbol("powf", &powf);
160 #endif
161 
162 #if defined(_WIN32)
163     if (KNOB_DUMP_SHADER_IR)
164     {
165         CreateDirectory(INTEL_OUTPUT_DIR, NULL);
166         CreateDirectory(SWR_OUTPUT_DIR, NULL);
167         CreateDirectory(JITTER_OUTPUT_DIR, NULL);
168     }
169 #endif
170 }
171 
172 //////////////////////////////////////////////////////////////////////////
173 /// @brief Create new LLVM module.
SetupNewModule()174 void JitManager::SetupNewModule()
175 {
176     SWR_ASSERT(mIsModuleFinalized == true && "Current module is not finalized!");
177 
178     std::stringstream fnName("JitModule", std::ios_base::in | std::ios_base::out | std::ios_base::ate);
179     fnName << mJitNumber++;
180     std::unique_ptr<Module> newModule(new Module(fnName.str(), mContext));
181     mpCurrentModule = newModule.get();
182 #if defined(_WIN32)
183     // Needed for MCJIT on windows
184     Triple hostTriple(sys::getProcessTriple());
185     hostTriple.setObjectFormat(Triple::ELF);
186     newModule->setTargetTriple(hostTriple.getTriple());
187 #endif // _WIN32
188 
189     mpExec->addModule(std::move(newModule));
190     mIsModuleFinalized = false;
191 }
192 
193 //////////////////////////////////////////////////////////////////////////
194 /// @brief Create new LLVM module from IR.
SetupModuleFromIR(const uint8_t * pIR)195 bool JitManager::SetupModuleFromIR(const uint8_t *pIR)
196 {
197     std::unique_ptr<MemoryBuffer> pMem = MemoryBuffer::getMemBuffer(StringRef((const char*)pIR), "");
198 
199     SMDiagnostic Err;
200     std::unique_ptr<Module> newModule = parseIR(pMem.get()->getMemBufferRef(), Err, mContext);
201 
202     SWR_REL_ASSERT(
203         !(newModule == nullptr),
204         "Parse failed!\n"
205         "%s", Err.getMessage().data());
206     if (newModule == nullptr)
207     {
208         return false;
209     }
210 
211 #if HAVE_LLVM == 0x307
212     // llvm-3.7 has mismatched setDataLyout/getDataLayout APIs
213     newModule->setDataLayout(*mpExec->getDataLayout());
214 #else
215     newModule->setDataLayout(mpExec->getDataLayout());
216 #endif
217 
218     mpCurrentModule = newModule.get();
219 #if defined(_WIN32)
220     // Needed for MCJIT on windows
221     Triple hostTriple(sys::getProcessTriple());
222     hostTriple.setObjectFormat(Triple::ELF);
223     newModule->setTargetTriple(hostTriple.getTriple());
224 #endif // _WIN32
225 
226     mpExec->addModule(std::move(newModule));
227     mIsModuleFinalized = false;
228 
229     return true;
230 }
231 
232 //////////////////////////////////////////////////////////////////////////
233 /// @brief Dump function x86 assembly to file.
234 /// @note This should only be called after the module has been jitted to x86 and the
235 ///       module will not be further accessed.
DumpAsm(Function * pFunction,const char * fileName)236 void JitManager::DumpAsm(Function* pFunction, const char* fileName)
237 {
238     if (KNOB_DUMP_SHADER_IR)
239     {
240 
241 #if defined(_WIN32)
242         DWORD pid = GetCurrentProcessId();
243         TCHAR procname[MAX_PATH];
244         GetModuleFileName(NULL, procname, MAX_PATH);
245         const char* pBaseName = strrchr(procname, '\\');
246         std::stringstream outDir;
247         outDir << JITTER_OUTPUT_DIR << pBaseName << "_" << pid << std::ends;
248         CreateDirectory(outDir.str().c_str(), NULL);
249 #endif
250 
251         std::error_code EC;
252         Module* pModule = pFunction->getParent();
253         const char *funcName = pFunction->getName().data();
254         char fName[256];
255 #if defined(_WIN32)
256         sprintf(fName, "%s\\%s.%s.asm", outDir.str().c_str(), funcName, fileName);
257 #else
258         sprintf(fName, "%s.%s.asm", funcName, fileName);
259 #endif
260 
261 #if HAVE_LLVM == 0x306
262         raw_fd_ostream fd(fName, EC, llvm::sys::fs::F_None);
263         formatted_raw_ostream filestream(fd);
264 #else
265         raw_fd_ostream filestream(fName, EC, llvm::sys::fs::F_None);
266 #endif
267 
268         legacy::PassManager* pMPasses = new legacy::PassManager();
269         auto* pTarget = mpExec->getTargetMachine();
270         pTarget->Options.MCOptions.AsmVerbose = true;
271         pTarget->addPassesToEmitFile(*pMPasses, filestream, TargetMachine::CGFT_AssemblyFile);
272         pMPasses->run(*pModule);
273         delete pMPasses;
274         pTarget->Options.MCOptions.AsmVerbose = false;
275     }
276 }
277 
278 //////////////////////////////////////////////////////////////////////////
279 /// @brief Dump function to file.
DumpToFile(Function * f,const char * fileName)280 void JitManager::DumpToFile(Function *f, const char *fileName)
281 {
282     if (KNOB_DUMP_SHADER_IR)
283     {
284 #if defined(_WIN32)
285         DWORD pid = GetCurrentProcessId();
286         TCHAR procname[MAX_PATH];
287         GetModuleFileName(NULL, procname, MAX_PATH);
288         const char* pBaseName = strrchr(procname, '\\');
289         std::stringstream outDir;
290         outDir << JITTER_OUTPUT_DIR << pBaseName << "_" << pid << std::ends;
291         CreateDirectory(outDir.str().c_str(), NULL);
292 #endif
293 
294         std::error_code EC;
295         const char *funcName = f->getName().data();
296         char fName[256];
297 #if defined(_WIN32)
298         sprintf(fName, "%s\\%s.%s.ll", outDir.str().c_str(), funcName, fileName);
299 #else
300         sprintf(fName, "%s.%s.ll", funcName, fileName);
301 #endif
302         raw_fd_ostream fd(fName, EC, llvm::sys::fs::F_None);
303         Module* pModule = f->getParent();
304         pModule->print(fd, nullptr);
305 
306 #if defined(_WIN32)
307         sprintf(fName, "%s\\cfg.%s.%s.dot", outDir.str().c_str(), funcName, fileName);
308 #else
309         sprintf(fName, "cfg.%s.%s.dot", funcName, fileName);
310 #endif
311         fd.flush();
312 
313         raw_fd_ostream fd_cfg(fName, EC, llvm::sys::fs::F_Text);
314         WriteGraph(fd_cfg, (const Function*)f);
315 
316         fd_cfg.flush();
317     }
318 }
319 
320 extern "C"
321 {
322     bool g_DllActive = true;
323 
324     //////////////////////////////////////////////////////////////////////////
325     /// @brief Create JIT context.
326     /// @param simdWidth - SIMD width to be used in generated program.
JitCreateContext(uint32_t targetSimdWidth,const char * arch,const char * core)327     HANDLE JITCALL JitCreateContext(uint32_t targetSimdWidth, const char* arch, const char* core)
328     {
329         return new JitManager(targetSimdWidth, arch, core);
330     }
331 
332     //////////////////////////////////////////////////////////////////////////
333     /// @brief Destroy JIT context.
JitDestroyContext(HANDLE hJitContext)334     void JITCALL JitDestroyContext(HANDLE hJitContext)
335     {
336         if (g_DllActive)
337         {
338             delete reinterpret_cast<JitManager*>(hJitContext);
339         }
340     }
341 }
342