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 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. 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. 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. 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. 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. 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