1 /*========================== begin_copyright_notice ============================
2
3 Copyright (C) 2019-2021 Intel Corporation
4
5 SPDX-License-Identifier: MIT
6
7 ============================= end_copyright_notice ===========================*/
8
9 #include "Compiler/IGCPassSupport.h"
10 #include "Compiler/InitializePasses.h"
11 #include "Compiler/CodeGenPublic.h"
12 #include "common/secure_mem.h"
13 #include "DynamicTextureFolding.h"
14 #include "Probe/Assertion.h"
15
16 using namespace llvm;
17 using namespace IGC;
18
19 // Register pass to igc-opt
20 #define PASS_FLAG "igc-dynamic-texture-folding"
21 #define PASS_DESCRIPTION "dynamic texture folding"
22 #define PASS_CFG_ONLY false
23 #define PASS_ANALYSIS false
24 IGC_INITIALIZE_PASS_BEGIN(DynamicTextureFolding, PASS_FLAG, PASS_DESCRIPTION, PASS_CFG_ONLY, PASS_ANALYSIS)
25 IGC_INITIALIZE_PASS_END(DynamicTextureFolding, PASS_FLAG, PASS_DESCRIPTION, PASS_CFG_ONLY, PASS_ANALYSIS)
26
27 char DynamicTextureFolding::ID = 0;
28
29 #define DEBUG_TYPE "DynamicTextureFolding"
30
DynamicTextureFolding()31 DynamicTextureFolding::DynamicTextureFolding() : FunctionPass(ID)
32 {
33 initializeDynamicTextureFoldingPass(*PassRegistry::getPassRegistry());
34 }
35
FoldSingleTextureValue(CallInst & I)36 void DynamicTextureFolding::FoldSingleTextureValue(CallInst& I)
37 {
38 ModuleMetaData* modMD = m_context->getModuleMetaData();
39
40 unsigned addrSpace = 0;
41 if (SampleIntrinsic *sInst = dyn_cast<SampleIntrinsic>(&I))
42 {
43 addrSpace = sInst->getTextureValue()->getType()->getPointerAddressSpace();
44 }
45 else if (SamplerLoadIntrinsic * lInst = dyn_cast<SamplerLoadIntrinsic>(&I))
46 {
47 addrSpace = lInst->getTextureValue()->getType()->getPointerAddressSpace();
48 }
49 else
50 {
51 return;
52 }
53
54 bool directIdx = false;
55 uint textureIndex = 0;
56 DecodeAS4GFXResource(addrSpace, directIdx, textureIndex);
57
58 // if the current texture index is found in modMD as uniform texture, replace the texture load/sample as constant.
59 auto it = modMD->inlineDynTextures.find(textureIndex);
60 if (it != modMD->inlineDynTextures.end())
61 {
62 for (auto iter = I.user_begin(); iter != I.user_end(); iter++)
63 {
64 if (llvm::ExtractElementInst* pExtract = llvm::dyn_cast<llvm::ExtractElementInst>(*iter))
65 {
66 if (llvm::ConstantInt* pIdx = llvm::dyn_cast<llvm::ConstantInt>(pExtract->getIndexOperand()))
67 {
68 if ((&I)->getType()->isIntOrIntVectorTy())
69 {
70 pExtract->replaceAllUsesWith(ConstantInt::get((pExtract)->getType(), (it->second[(uint32_t)(pIdx->getZExtValue())])));
71 }
72 else if ((&I)->getType()->isFPOrFPVectorTy())
73 {
74 pExtract->replaceAllUsesWith(ConstantFP::get((pExtract)->getType(), *(float*)&(it->second[(uint32_t)(pIdx->getZExtValue())])));
75 }
76 }
77 }
78 }
79 }
80 }
ShiftByLOD(Instruction * pCall,unsigned int dimension,Value * val)81 Value* DynamicTextureFolding::ShiftByLOD(Instruction* pCall, unsigned int dimension, Value* val)
82 {
83 IRBuilder<> builder(pCall);
84 Value* tmp = builder.getInt32(dimension + 1);
85 Value* lod = pCall->getOperand(1);
86 builder.SetInsertPoint(pCall);
87 Value* Lshr = builder.CreateLShr(tmp, lod);
88 if (val)
89 return builder.CreateMul(Lshr, val);
90 else
91 return Lshr;
92 }
FoldResInfoValue(llvm::GenIntrinsicInst * pCall)93 void DynamicTextureFolding::FoldResInfoValue(llvm::GenIntrinsicInst* pCall)
94 {
95 ModuleMetaData* modMD = m_context->getModuleMetaData();
96 llvm::Value* r;
97 llvm::Value* g;
98 llvm::Value* b;
99 llvm::Value* a;
100 BufferType bufType;
101 bool directIdx = false;
102 uint textureIndex = 0;
103 Value* texOp = pCall->getOperand(0);
104 unsigned addrSpace = texOp->getType()->getPointerAddressSpace();
105 bufType = DecodeAS4GFXResource(addrSpace, directIdx, textureIndex);
106 if (!directIdx || (bufType != RESOURCE && bufType != UAV))
107 return;
108 auto I32Ty = Type::getInt32Ty(pCall->getContext());
109 for(unsigned int i = 0; i < modMD->inlineResInfoData.size();i++)
110 {
111 if (textureIndex == modMD->inlineResInfoData[i].textureID)
112 {
113 ConstantInt* isLODConstant = dyn_cast<ConstantInt>(pCall->getOperand(1));
114 a = ConstantInt::get(I32Ty, modMD->inlineResInfoData[i].MipCount);
115 switch (modMD->inlineResInfoData[i].SurfaceType)
116 {
117 case GFXSURFACESTATE_SURFACETYPE_1D:
118 {
119 g = ConstantInt::get(I32Ty, (modMD->inlineResInfoData[i].SurfaceArray > 0) ? modMD->inlineResInfoData[i].Depth + 1 : 0);
120 b = ConstantInt::get(I32Ty, 0);
121 if (isLODConstant)
122 {
123 uint64_t lod = isLODConstant->getZExtValue();
124 r = ConstantInt::get(I32Ty, (modMD->inlineResInfoData[i].WidthOrBufferSize + 1) >> lod);
125 }
126 else
127 {
128 r = ShiftByLOD(dyn_cast<Instruction>(pCall), modMD->inlineResInfoData[i].WidthOrBufferSize, nullptr);
129 }
130 break;
131 }
132 case GFXSURFACESTATE_SURFACETYPE_2D:
133 {
134 b = ConstantInt::get(I32Ty,(modMD->inlineResInfoData[i].SurfaceArray > 0) ? modMD->inlineResInfoData[i].Depth + 1 : 0);
135 if (isLODConstant)
136 {
137 uint64_t lod = isLODConstant->getZExtValue();
138 r = ConstantInt::get(I32Ty, ((modMD->inlineResInfoData[i].WidthOrBufferSize + 1) >> lod)* (modMD->inlineResInfoData[i].QWidth + 1));
139 g = ConstantInt::get(I32Ty, ((modMD->inlineResInfoData[i].Height + 1) >> lod)* (modMD->inlineResInfoData[i].QHeight + 1));
140 }
141 else
142 {
143 Value* QWidth = ConstantInt::get(I32Ty,(modMD->inlineResInfoData[i].QWidth + 1));
144 Value* QHeight = ConstantInt::get(I32Ty, (modMD->inlineResInfoData[i].QHeight + 1));
145 r = ShiftByLOD(dyn_cast<Instruction>(pCall), modMD->inlineResInfoData[i].WidthOrBufferSize, QWidth);
146 g = ShiftByLOD(dyn_cast<Instruction>(pCall), modMD->inlineResInfoData[i].Height, QHeight);
147 }
148 break;
149 }
150 case GFXSURFACESTATE_SURFACETYPE_3D:
151 {
152 if(isLODConstant)
153 {
154 uint64_t lod = isLODConstant->getZExtValue();
155 r = ConstantInt::get(I32Ty,((modMD->inlineResInfoData[i].WidthOrBufferSize + 1) >> lod));
156 g = ConstantInt::get(I32Ty, ((modMD->inlineResInfoData[i].Height + 1) >> lod));
157 b = ConstantInt::get(I32Ty, ((modMD->inlineResInfoData[i].Depth + 1) >> lod));
158 }
159 else
160 {
161 r = ShiftByLOD(dyn_cast<Instruction>(pCall), modMD->inlineResInfoData[i].WidthOrBufferSize, nullptr);
162 g = ShiftByLOD(dyn_cast<Instruction>(pCall), modMD->inlineResInfoData[i].Height, nullptr);
163 b = ShiftByLOD(dyn_cast<Instruction>(pCall), modMD->inlineResInfoData[i].Depth, nullptr);
164 }
165 break;
166 }
167 case GFXSURFACESTATE_SURFACETYPE_CUBE:
168 {
169 b = ConstantInt::get(I32Ty, (modMD->inlineResInfoData[i].SurfaceArray > 0) ? modMD->inlineResInfoData[i].Depth + 1 : 0);
170 if (isLODConstant)
171 {
172 uint64_t lod = isLODConstant->getZExtValue();
173 r = ConstantInt::get(I32Ty, ((modMD->inlineResInfoData[i].WidthOrBufferSize + 1) >> lod));
174 g = ConstantInt::get(I32Ty, ((modMD->inlineResInfoData[i].Height + 1) >> lod));
175 }
176 else
177 {
178 r = ShiftByLOD(dyn_cast<Instruction>(pCall), modMD->inlineResInfoData[i].WidthOrBufferSize, nullptr);
179 g = ShiftByLOD(dyn_cast<Instruction>(pCall), modMD->inlineResInfoData[i].Height, nullptr);
180 }
181 break;
182 }
183 case GFXSURFACESTATE_SURFACETYPE_BUFFER:
184 case GFXSURFACESTATE_SURFACETYPE_STRBUF:
185 case GFXSURFACESTATE_SURFACETYPE_SCRATCH:
186
187 {
188 r = (modMD->inlineResInfoData[i].WidthOrBufferSize != UINT_MAX) ? ConstantInt::get(I32Ty, modMD->inlineResInfoData[i].WidthOrBufferSize) : 0;
189 g = 0;
190 b = 0;
191 a = 0;
192 break;
193 }
194 default:
195 {
196 r = 0;
197 g = 0;
198 b = 0;
199 a = 0;
200 break;
201 }
202 }
203 for (auto iter = pCall->user_begin(); iter != pCall->user_end(); iter++)
204 {
205 if (llvm::ExtractElementInst* pExtract = llvm::dyn_cast<llvm::ExtractElementInst>(*iter))
206 {
207 if (llvm::ConstantInt* pIdx = llvm::dyn_cast<llvm::ConstantInt>(pExtract->getIndexOperand()))
208 {
209 if (pIdx->getZExtValue() == 0)
210 {
211 pExtract->replaceAllUsesWith(r);
212 pExtract->eraseFromParent();
213 }
214 else if (pIdx->getZExtValue() == 1)
215 {
216 pExtract->replaceAllUsesWith(g);
217 pExtract->eraseFromParent();
218 }
219 else if (pIdx->getZExtValue() == 2)
220 {
221 pExtract->replaceAllUsesWith(b);
222 pExtract->eraseFromParent();
223 }
224 else if (pIdx->getZExtValue() == 3)
225 {
226 pExtract->replaceAllUsesWith(a);
227 pExtract->eraseFromParent();
228 }
229 }
230 }
231 }
232 }
233 }
234 }
visitCallInst(CallInst & I)235 void DynamicTextureFolding::visitCallInst(CallInst& I)
236 {
237 ModuleMetaData* modMD = m_context->getModuleMetaData();
238 if (GenIntrinsicInst* pCall = dyn_cast<GenIntrinsicInst>(&I))
239 {
240 auto ID = pCall->getIntrinsicID();
241 if (!IGC_IS_FLAG_ENABLED(DisableDynamicTextureFolding) && modMD->inlineDynTextures.size() != 0)
242 {
243 if (ID == GenISAIntrinsic::GenISA_sampleptr ||
244 ID == GenISAIntrinsic::GenISA_sampleLptr ||
245 ID == GenISAIntrinsic::GenISA_sampleBptr ||
246 ID == GenISAIntrinsic::GenISA_sampleDptr ||
247 ID == GenISAIntrinsic::GenISA_ldptr)
248 {
249 FoldSingleTextureValue(I);
250 }
251 }
252 if (!IGC_IS_FLAG_ENABLED(DisableDynamicResInfoFolding) && ID == GenISAIntrinsic::GenISA_resinfoptr)
253 {
254 if ( modMD->inlineResInfoData.size() > 0)
255 {
256 FoldResInfoValue(pCall);
257 }
258 else
259 {
260 BufferType bufType;
261 bool directIdx = false;
262 uint textureIndex = 0;
263 Value* texOp = pCall->getOperand(0);
264 unsigned addrSpace = texOp->getType()->getPointerAddressSpace();
265 bufType = DecodeAS4GFXResource(addrSpace, directIdx, textureIndex);
266 m_ResInfoFoldingOutput[textureIndex].textureID = textureIndex;
267 if (!directIdx || (bufType != RESOURCE && bufType != UAV))
268 return;
269 for (auto UI = pCall->user_begin(), UE = pCall->user_end(); UI != UE; ++UI)
270 {
271 if (llvm::ExtractElementInst* useInst = dyn_cast<llvm::ExtractElementInst>(*UI))
272 {
273 ConstantInt* eltID = dyn_cast<ConstantInt>(useInst->getOperand(1));
274 if (!eltID)
275 continue;
276 m_ResInfoFoldingOutput[textureIndex].value[int_cast<unsigned>(eltID->getZExtValue())] = true;
277 }
278 }
279 }
280 }
281 return;
282 }
283 }
284
285 template<typename ContextT>
copyResInfoData(ContextT * pShaderCtx)286 void DynamicTextureFolding::copyResInfoData(ContextT* pShaderCtx)
287 {
288 pShaderCtx->programOutput.m_ResInfoFoldingOutput.clear();
289 for (unsigned int i = 0; i < m_ResInfoFoldingOutput.size(); i++)
290 {
291 pShaderCtx->programOutput.m_ResInfoFoldingOutput.push_back(m_ResInfoFoldingOutput[i]);
292 }
293 }
doFinalization(llvm::Module & M)294 bool DynamicTextureFolding::doFinalization(llvm::Module& M)
295 {
296 if (m_ResInfoFoldingOutput.size() != 0)
297 {
298 if (m_context->type == ShaderType::PIXEL_SHADER)
299 {
300 PixelShaderContext* pShaderCtx = static_cast <PixelShaderContext*>(m_context);
301 copyResInfoData(pShaderCtx);
302 }
303 else if (m_context->type == ShaderType::VERTEX_SHADER)
304 {
305 VertexShaderContext* pShaderCtx = static_cast <VertexShaderContext*>(m_context);
306 copyResInfoData(pShaderCtx);
307 }
308 else if (m_context->type == ShaderType::GEOMETRY_SHADER)
309 {
310 GeometryShaderContext* pShaderCtx = static_cast <GeometryShaderContext*>(m_context);
311 copyResInfoData(pShaderCtx);
312 }
313 else if (m_context->type == ShaderType::HULL_SHADER)
314 {
315 HullShaderContext* pShaderCtx = static_cast <HullShaderContext*>(m_context);
316 copyResInfoData(pShaderCtx);
317 }
318 else if (m_context->type == ShaderType::DOMAIN_SHADER)
319 {
320 DomainShaderContext* pShaderCtx = static_cast <DomainShaderContext*>(m_context);
321 copyResInfoData(pShaderCtx);
322 }
323 else if (m_context->type == ShaderType::COMPUTE_SHADER)
324 {
325 ComputeShaderContext* pShaderCtx = static_cast <ComputeShaderContext*>(m_context);
326 copyResInfoData(pShaderCtx);
327 }
328 }
329 return false;
330 }
331
runOnFunction(Function & F)332 bool DynamicTextureFolding::runOnFunction(Function& F)
333 {
334 m_context = getAnalysis<CodeGenContextWrapper>().getCodeGenContext();
335 visit(F);
336 return false;
337 }
338