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.h 24 * 25 * @brief JitManager contains the LLVM data structures used for JIT generation 26 * 27 * Notes: 28 * 29 ******************************************************************************/ 30 #pragma once 31 32 #include "jit_pch.hpp" 33 #include "common/isa.hpp" 34 #include <llvm/IR/AssemblyAnnotationWriter.h> 35 36 37 ////////////////////////////////////////////////////////////////////////// 38 /// JitInstructionSet 39 /// @brief Subclass of InstructionSet that allows users to override 40 /// the reporting of support for certain ISA features. This allows capping 41 /// the jitted code to a certain feature level, e.g. jit AVX level code on 42 /// a platform that supports AVX2. 43 ////////////////////////////////////////////////////////////////////////// 44 class JitInstructionSet : public InstructionSet 45 { 46 public: JitInstructionSet(const char * requestedIsa)47 JitInstructionSet(const char* requestedIsa) : isaRequest(requestedIsa) 48 { 49 std::transform(isaRequest.begin(), isaRequest.end(), isaRequest.begin(), ::tolower); 50 51 if (isaRequest == "avx") 52 { 53 bForceAVX = true; 54 bForceAVX2 = false; 55 bForceAVX512 = false; 56 } 57 else if (isaRequest == "avx2") 58 { 59 bForceAVX = false; 60 bForceAVX2 = true; 61 bForceAVX512 = false; 62 } 63 else if (isaRequest == "avx512") 64 { 65 bForceAVX = false; 66 bForceAVX2 = false; 67 bForceAVX512 = true; 68 } 69 }; 70 AVX2(void)71 bool AVX2(void) { return bForceAVX ? 0 : InstructionSet::AVX2(); } AVX512F(void)72 bool AVX512F(void) { return (bForceAVX | bForceAVX2) ? 0 : InstructionSet::AVX512F(); } AVX512ER(void)73 bool AVX512ER(void) { return (bForceAVX | bForceAVX2) ? 0 : InstructionSet::AVX512ER(); } BMI2(void)74 bool BMI2(void) { return bForceAVX ? 0 : InstructionSet::BMI2(); } 75 76 private: 77 bool bForceAVX = false; 78 bool bForceAVX2 = false; 79 bool bForceAVX512 = false; 80 std::string isaRequest; 81 }; 82 83 struct JitLLVMContext : llvm::LLVMContext 84 { 85 }; 86 87 ////////////////////////////////////////////////////////////////////////// 88 /// JitCache 89 ////////////////////////////////////////////////////////////////////////// 90 struct JitManager; // Forward Decl 91 class JitCache : public llvm::ObjectCache 92 { 93 public: 94 /// constructor 95 JitCache(); ~JitCache()96 virtual ~JitCache() {} 97 Init(JitManager * pJitMgr,const llvm::StringRef & cpu,llvm::CodeGenOpt::Level level)98 void Init(JitManager* pJitMgr, const llvm::StringRef& cpu, llvm::CodeGenOpt::Level level) 99 { 100 mCpu = cpu.str(); 101 mpJitMgr = pJitMgr; 102 mOptLevel = level; 103 } 104 105 /// notifyObjectCompiled - Provides a pointer to compiled code for Module M. 106 void notifyObjectCompiled(const llvm::Module* M, llvm::MemoryBufferRef Obj) override; 107 108 /// Returns a pointer to a newly allocated MemoryBuffer that contains the 109 /// object which corresponds with Module M, or 0 if an object is not 110 /// available. 111 std::unique_ptr<llvm::MemoryBuffer> getObject(const llvm::Module* M) override; 112 GetModuleCacheDir()113 const char* GetModuleCacheDir() { return mModuleCacheDir.c_str(); } 114 115 private: 116 std::string mCpu; 117 llvm::SmallString<MAX_PATH> mCacheDir; 118 llvm::SmallString<MAX_PATH> mModuleCacheDir; 119 uint32_t mCurrentModuleCRC = 0; 120 JitManager* mpJitMgr = nullptr; 121 llvm::CodeGenOpt::Level mOptLevel = llvm::CodeGenOpt::None; 122 123 /// Calculate actual directory where module will be cached. 124 /// This is always a subdirectory of mCacheDir. Full absolute 125 /// path name will be stored in mCurrentModuleCacheDir 126 void CalcModuleCacheDir(); 127 }; 128 129 ////////////////////////////////////////////////////////////////////////// 130 /// JitManager 131 ////////////////////////////////////////////////////////////////////////// 132 struct JitManager 133 { 134 JitManager(uint32_t w, const char* arch, const char* core); ~JitManagerJitManager135 ~JitManager() 136 { 137 for (auto* pExec : mvExecEngines) 138 { 139 delete pExec; 140 } 141 } 142 143 JitLLVMContext mContext; ///< LLVM compiler 144 llvm::IRBuilder<> mBuilder; ///< LLVM IR Builder 145 llvm::ExecutionEngine* mpExec; 146 std::vector<llvm::ExecutionEngine*> mvExecEngines; 147 JitCache mCache; 148 llvm::StringRef mHostCpuName; 149 llvm::CodeGenOpt::Level mOptLevel; 150 151 // Need to be rebuilt after a JIT and before building new IR 152 llvm::Module* mpCurrentModule; 153 bool mIsModuleFinalized; 154 uint32_t mJitNumber; 155 156 uint32_t mVWidth; 157 158 bool mUsingAVX512 = false; 159 160 // fetch shader types 161 llvm::FunctionType* mFetchShaderTy; 162 163 JitInstructionSet mArch; 164 165 // Debugging support 166 std::unordered_map<llvm::StructType*, llvm::DIType*> mDebugStructMap; 167 168 void CreateExecEngine(std::unique_ptr<llvm::Module> M); 169 void SetupNewModule(); 170 171 void DumpAsm(llvm::Function* pFunction, const char* fileName); 172 static void DumpToFile(llvm::Function* f, const char* fileName); 173 static void DumpToFile(llvm::Module* M, 174 const char* fileName, 175 llvm::AssemblyAnnotationWriter* annotater = nullptr); 176 static std::string GetOutputDir(); 177 178 // Debugging support methods 179 llvm::DIType* GetDebugType(llvm::Type* pTy); 180 llvm::DIType* GetDebugIntegerType(llvm::Type* pTy); 181 llvm::DIType* GetDebugArrayType(llvm::Type* pTy); 182 llvm::DIType* GetDebugVectorType(llvm::Type* pTy); 183 llvm::DIType* GetDebugFunctionType(llvm::Type* pTy); 184 GetDebugStructTypeJitManager185 llvm::DIType* GetDebugStructType(llvm::Type* pType) 186 { 187 llvm::StructType* pStructTy = llvm::cast<llvm::StructType>(pType); 188 if (mDebugStructMap.find(pStructTy) == mDebugStructMap.end()) 189 { 190 return nullptr; 191 } 192 return mDebugStructMap[pStructTy]; 193 } 194 195 llvm::DIType* 196 CreateDebugStructType(llvm::StructType* pType, 197 const std::string& name, 198 llvm::DIFile* pFile, 199 uint32_t lineNum, 200 const std::vector<std::pair<std::string, uint32_t>>& members); 201 }; 202 203 class InterleaveAssemblyAnnotater : public llvm::AssemblyAnnotationWriter 204 { 205 public: 206 void emitInstructionAnnot(const llvm::Instruction* pInst, 207 llvm::formatted_raw_ostream& OS) override; 208 std::vector<std::string> mAssembly; 209 210 private: 211 uint32_t mCurrentLineNo = 0; 212 }; 213