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