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 ******************************************************************************/
31 #pragma warning(disable: 4800 4146 4244 4267 4355 4996)
35 #include "JitManager.h"
36 #include "fetch_jit.h"
39 #include "llvm/ADT/Triple.h"
41 #include "llvm/IR/Function.h"
42 #include "llvm/Support/DynamicLibrary.h"
44 #include "llvm/Support/MemoryBuffer.h"
45 #include "llvm/Support/SourceMgr.h"
47 #include "llvm/Analysis/CFGPrinter.h"
48 #include "llvm/IRReader/IRReader.h"
49 #include "llvm/Target/TargetMachine.h"
50 #include "llvm/Support/FormattedStream.h"
52 #if LLVM_USE_INTEL_JITEVENTS
53 #include "llvm/ExecutionEngine/JITEventListener.h"
56 #include "core/state.h"
57 #include "common/containers.hpp"
59 #include "state_llvm.h"
66 #define INTEL_OUTPUT_DIR "c:\\Intel"
67 #define SWR_OUTPUT_DIR INTEL_OUTPUT_DIR "\\SWR"
68 #define JITTER_OUTPUT_DIR SWR_OUTPUT_DIR "\\Jitter"
73 //////////////////////////////////////////////////////////////////////////
74 /// @brief Contructor for JitManager.
75 /// @param simdWidth - SIMD width to be used in generated program.
76 JitManager::JitManager(uint32_t simdWidth
, const char *arch
)
77 : mContext(), mBuilder(mContext
), mIsModuleFinalized(true), mJitNumber(0), mVWidth(simdWidth
), mArch(arch
)
79 InitializeNativeTarget();
80 InitializeNativeTargetAsmPrinter();
81 InitializeNativeTargetDisassembler();
84 tOpts
.AllowFPOpFusion
= FPOpFusion::Fast
;
85 tOpts
.NoInfsFPMath
= false;
86 tOpts
.NoNaNsFPMath
= false;
87 tOpts
.UnsafeFPMath
= true;
89 #if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7
90 tOpts
.NoFramePointerElim
= true;
94 //tOpts.PrintMachineCode = true;
96 std::stringstream
fnName("JitModule", std::ios_base::in
| std::ios_base::out
| std::ios_base::ate
);
97 fnName
<< mJitNumber
++;
98 std::unique_ptr
<Module
> newModule(new Module(fnName
.str(), mContext
));
99 mpCurrentModule
= newModule
.get();
101 auto &&EB
= EngineBuilder(std::move(newModule
));
102 EB
.setTargetOptions(tOpts
);
103 EB
.setOptLevel(CodeGenOpt::Aggressive
);
105 StringRef hostCPUName
;
107 // force JIT to use the same CPU arch as the rest of swr
110 assert(0 && "Implement AVX512 jitter");
111 hostCPUName
= sys::getHostCPUName();
117 else if(mArch
.AVX2())
119 hostCPUName
= StringRef("core-avx2");
129 hostCPUName
= StringRef("core-avx-i");
133 hostCPUName
= StringRef("corei7-avx");
142 hostCPUName
= sys::getHostCPUName();
149 EB
.setMCPU(hostCPUName
);
152 // Needed for MCJIT on windows
153 Triple
hostTriple(sys::getProcessTriple());
154 hostTriple
.setObjectFormat(Triple::ELF
);
155 mpCurrentModule
->setTargetTriple(hostTriple
.getTriple());
158 mpExec
= EB
.create();
160 #if LLVM_USE_INTEL_JITEVENTS
161 JITEventListener
*vTune
= JITEventListener::createIntelJITEventListener();
162 mpExec
->RegisterJITEventListener(vTune
);
165 mFP32Ty
= Type::getFloatTy(mContext
); // float type
166 mInt8Ty
= Type::getInt8Ty(mContext
);
167 mInt32Ty
= Type::getInt32Ty(mContext
); // int type
168 mInt64Ty
= Type::getInt64Ty(mContext
); // int type
169 mV4FP32Ty
= StructType::get(mContext
, std::vector
<Type
*>(4, mFP32Ty
), false); // vector4 float type (represented as structure)
170 mV4Int32Ty
= StructType::get(mContext
, std::vector
<Type
*>(4, mInt32Ty
), false); // vector4 int type
172 // fetch function signature
173 // typedef void(__cdecl *PFN_FETCH_FUNC)(SWR_FETCH_CONTEXT& fetchInfo, simdvertex& out);
174 std::vector
<Type
*> fsArgs
;
175 fsArgs
.push_back(PointerType::get(Gen_SWR_FETCH_CONTEXT(this), 0));
176 fsArgs
.push_back(PointerType::get(Gen_simdvertex(this), 0));
178 mFetchShaderTy
= FunctionType::get(Type::getVoidTy(mContext
), fsArgs
, false);
180 mSimtFP32Ty
= VectorType::get(mFP32Ty
, mVWidth
);
181 mSimtInt32Ty
= VectorType::get(mInt32Ty
, mVWidth
);
183 mSimdVectorTy
= StructType::get(mContext
, std::vector
<Type
*>(4, mSimtFP32Ty
), false);
184 mSimdVectorInt32Ty
= StructType::get(mContext
, std::vector
<Type
*>(4, mSimtInt32Ty
), false);
187 // explicitly instantiate used symbols from potentially staticly linked libs
188 sys::DynamicLibrary::AddSymbol("exp2f", &exp2f
);
189 sys::DynamicLibrary::AddSymbol("log2f", &log2f
);
190 sys::DynamicLibrary::AddSymbol("sinf", &sinf
);
191 sys::DynamicLibrary::AddSymbol("cosf", &cosf
);
192 sys::DynamicLibrary::AddSymbol("powf", &powf
);
196 if (KNOB_DUMP_SHADER_IR
)
198 CreateDirectory(INTEL_OUTPUT_DIR
, NULL
);
199 CreateDirectory(SWR_OUTPUT_DIR
, NULL
);
200 CreateDirectory(JITTER_OUTPUT_DIR
, NULL
);
205 //////////////////////////////////////////////////////////////////////////
206 /// @brief Create new LLVM module.
207 void JitManager::SetupNewModule()
209 SWR_ASSERT(mIsModuleFinalized
== true && "Current module is not finalized!");
211 std::stringstream
fnName("JitModule", std::ios_base::in
| std::ios_base::out
| std::ios_base::ate
);
212 fnName
<< mJitNumber
++;
213 std::unique_ptr
<Module
> newModule(new Module(fnName
.str(), mContext
));
214 mpCurrentModule
= newModule
.get();
216 // Needed for MCJIT on windows
217 Triple
hostTriple(sys::getProcessTriple());
218 hostTriple
.setObjectFormat(Triple::ELF
);
219 newModule
->setTargetTriple(hostTriple
.getTriple());
222 mpExec
->addModule(std::move(newModule
));
223 mIsModuleFinalized
= false;
226 //////////////////////////////////////////////////////////////////////////
227 /// @brief Create new LLVM module from IR.
228 bool JitManager::SetupModuleFromIR(const uint8_t *pIR
)
230 std::unique_ptr
<MemoryBuffer
> pMem
= MemoryBuffer::getMemBuffer(StringRef((const char*)pIR
), "");
233 std::unique_ptr
<Module
> newModule
= parseIR(pMem
.get()->getMemBufferRef(), Err
, mContext
);
235 if (newModule
== nullptr)
237 SWR_ASSERT(0, "Parse failed! Check Err for details.");
241 mpCurrentModule
= newModule
.get();
243 // Needed for MCJIT on windows
244 Triple
hostTriple(sys::getProcessTriple());
245 hostTriple
.setObjectFormat(Triple::ELF
);
246 newModule
->setTargetTriple(hostTriple
.getTriple());
249 mpExec
->addModule(std::move(newModule
));
250 mIsModuleFinalized
= false;
256 //////////////////////////////////////////////////////////////////////////
257 /// @brief Dump function x86 assembly to file.
258 /// @note This should only be called after the module has been jitted to x86 and the
259 /// module will not be further accessed.
260 void JitManager::DumpAsm(Function
* pFunction
, const char* fileName
)
262 if (KNOB_DUMP_SHADER_IR
)
266 DWORD pid
= GetCurrentProcessId();
267 TCHAR procname
[MAX_PATH
];
268 GetModuleFileName(NULL
, procname
, MAX_PATH
);
269 const char* pBaseName
= strrchr(procname
, '\\');
270 std::stringstream outDir
;
271 outDir
<< JITTER_OUTPUT_DIR
<< pBaseName
<< "_" << pid
<< std::ends
;
272 CreateDirectory(outDir
.str().c_str(), NULL
);
276 Module
* pModule
= pFunction
->getParent();
277 const char *funcName
= pFunction
->getName().data();
280 sprintf(fName
, "%s\\%s.%s.asm", outDir
.str().c_str(), funcName
, fileName
);
282 sprintf(fName
, "%s.%s.asm", funcName
, fileName
);
285 #if HAVE_LLVM == 0x306
286 raw_fd_ostream
fd(fName
, EC
, llvm::sys::fs::F_None
);
287 formatted_raw_ostream
filestream(fd
);
289 raw_fd_ostream
filestream(fName
, EC
, llvm::sys::fs::F_None
);
292 legacy::PassManager
* pMPasses
= new legacy::PassManager();
293 auto* pTarget
= mpExec
->getTargetMachine();
294 pTarget
->Options
.MCOptions
.AsmVerbose
= true;
295 pTarget
->addPassesToEmitFile(*pMPasses
, filestream
, TargetMachine::CGFT_AssemblyFile
);
296 pMPasses
->run(*pModule
);
298 pTarget
->Options
.MCOptions
.AsmVerbose
= false;
302 //////////////////////////////////////////////////////////////////////////
303 /// @brief Dump function to file.
304 void JitManager::DumpToFile(Function
*f
, const char *fileName
)
306 if (KNOB_DUMP_SHADER_IR
)
309 DWORD pid
= GetCurrentProcessId();
310 TCHAR procname
[MAX_PATH
];
311 GetModuleFileName(NULL
, procname
, MAX_PATH
);
312 const char* pBaseName
= strrchr(procname
, '\\');
313 std::stringstream outDir
;
314 outDir
<< JITTER_OUTPUT_DIR
<< pBaseName
<< "_" << pid
<< std::ends
;
315 CreateDirectory(outDir
.str().c_str(), NULL
);
319 const char *funcName
= f
->getName().data();
322 sprintf(fName
, "%s\\%s.%s.ll", outDir
.str().c_str(), funcName
, fileName
);
324 sprintf(fName
, "%s.%s.ll", funcName
, fileName
);
326 raw_fd_ostream
fd(fName
, EC
, llvm::sys::fs::F_None
);
327 Module
* pModule
= f
->getParent();
328 pModule
->print(fd
, nullptr);
331 sprintf(fName
, "%s\\cfg.%s.%s.dot", outDir
.str().c_str(), funcName
, fileName
);
333 sprintf(fName
, "cfg.%s.%s.dot", funcName
, fileName
);
337 raw_fd_ostream
fd_cfg(fName
, EC
, llvm::sys::fs::F_Text
);
338 WriteGraph(fd_cfg
, (const Function
*)f
);
346 //////////////////////////////////////////////////////////////////////////
347 /// @brief Create JIT context.
348 /// @param simdWidth - SIMD width to be used in generated program.
349 HANDLE JITCALL
JitCreateContext(uint32_t targetSimdWidth
, const char* arch
)
351 return new JitManager(targetSimdWidth
, arch
);
354 //////////////////////////////////////////////////////////////////////////
355 /// @brief Destroy JIT context.
356 void JITCALL
JitDestroyContext(HANDLE hJitContext
)
358 delete reinterpret_cast<JitManager
*>(hJitContext
);