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 74using namespace llvm; 75using namespace SwrJit; 76 77////////////////////////////////////////////////////////////////////////// 78/// @brief Contructor for JitManager. 79/// @param simdWidth - SIMD width to be used in generated program. 80JitManager::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. 174void 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. 195bool 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. 236void 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. 280void 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 320extern "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. 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. 334 void JITCALL JitDestroyContext(HANDLE hJitContext) 335 { 336 if (g_DllActive) 337 { 338 delete reinterpret_cast<JitManager*>(hJitContext); 339 } 340 } 341} 342