swr/rast: Store cached files in multiple subdirs
[mesa.git] / src / gallium / drivers / swr / rasterizer / jitter / JitManager.h
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:
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
71 bool AVX2(void) { return bForceAVX ? 0 : InstructionSet::AVX2(); }
72 bool AVX512F(void) { return (bForceAVX | bForceAVX2) ? 0 : InstructionSet::AVX512F(); }
73 bool AVX512ER(void) { return (bForceAVX | bForceAVX2) ? 0 : InstructionSet::AVX512ER(); }
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();
96 virtual ~JitCache() {}
97
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
113 private:
114 std::string mCpu;
115 llvm::SmallString<MAX_PATH> mCacheDir;
116 llvm::SmallString<MAX_PATH> mModuleCacheDir;
117 uint32_t mCurrentModuleCRC = 0;
118 JitManager* mpJitMgr = nullptr;
119 llvm::CodeGenOpt::Level mOptLevel = llvm::CodeGenOpt::None;
120
121 /// Calculate actual directory where module will be cached.
122 /// This is always a subdirectory of mCacheDir. Full absolute
123 /// path name will be stored in mCurrentModuleCacheDir
124 void CalcModuleCacheDir();
125 };
126
127 //////////////////////////////////////////////////////////////////////////
128 /// JitManager
129 //////////////////////////////////////////////////////////////////////////
130 struct JitManager
131 {
132 JitManager(uint32_t w, const char* arch, const char* core);
133 ~JitManager()
134 {
135 for (auto* pExec : mvExecEngines)
136 {
137 delete pExec;
138 }
139 }
140
141 JitLLVMContext mContext; ///< LLVM compiler
142 llvm::IRBuilder<> mBuilder; ///< LLVM IR Builder
143 llvm::ExecutionEngine* mpExec;
144 std::vector<llvm::ExecutionEngine*> mvExecEngines;
145 JitCache mCache;
146 llvm::StringRef mHostCpuName;
147 llvm::CodeGenOpt::Level mOptLevel;
148
149 // Need to be rebuilt after a JIT and before building new IR
150 llvm::Module* mpCurrentModule;
151 bool mIsModuleFinalized;
152 uint32_t mJitNumber;
153
154 uint32_t mVWidth;
155
156 bool mUsingAVX512 = false;
157
158 // fetch shader types
159 llvm::FunctionType* mFetchShaderTy;
160
161 JitInstructionSet mArch;
162
163 // Debugging support
164 std::unordered_map<llvm::StructType*, llvm::DIType*> mDebugStructMap;
165
166 void CreateExecEngine(std::unique_ptr<llvm::Module> M);
167 void SetupNewModule();
168
169 void DumpAsm(llvm::Function* pFunction, const char* fileName);
170 static void DumpToFile(llvm::Function* f, const char* fileName);
171 static void DumpToFile(llvm::Module* M,
172 const char* fileName,
173 llvm::AssemblyAnnotationWriter* annotater = nullptr);
174 static std::string GetOutputDir();
175
176 // Debugging support methods
177 llvm::DIType* GetDebugType(llvm::Type* pTy);
178 llvm::DIType* GetDebugIntegerType(llvm::Type* pTy);
179 llvm::DIType* GetDebugArrayType(llvm::Type* pTy);
180 llvm::DIType* GetDebugVectorType(llvm::Type* pTy);
181 llvm::DIType* GetDebugFunctionType(llvm::Type* pTy);
182
183 llvm::DIType* GetDebugStructType(llvm::Type* pType)
184 {
185 llvm::StructType* pStructTy = llvm::cast<llvm::StructType>(pType);
186 if (mDebugStructMap.find(pStructTy) == mDebugStructMap.end())
187 {
188 return nullptr;
189 }
190 return mDebugStructMap[pStructTy];
191 }
192
193 llvm::DIType*
194 CreateDebugStructType(llvm::StructType* pType,
195 const std::string& name,
196 llvm::DIFile* pFile,
197 uint32_t lineNum,
198 const std::vector<std::pair<std::string, uint32_t>>& members);
199 };
200
201 class InterleaveAssemblyAnnotater : public llvm::AssemblyAnnotationWriter
202 {
203 public:
204 void emitInstructionAnnot(const llvm::Instruction* pInst,
205 llvm::formatted_raw_ostream& OS) override;
206 std::vector<std::string> mAssembly;
207
208 private:
209 uint32_t mCurrentLineNo = 0;
210 };