Home | History | Annotate | Download | only in jitter
      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