1 /*========================== begin_copyright_notice ============================
2 
3 Copyright (C) 2017-2021 Intel Corporation
4 
5 SPDX-License-Identifier: MIT
6 
7 ============================= end_copyright_notice ===========================*/
8 
9 #include "Compiler/Optimizer/OpenCLPasses/ImageFuncs/ImageFuncResolution.hpp"
10 #include "Compiler/Optimizer/OpenCLPasses/ImageFuncs/ImageFuncsAnalysis.hpp"
11 #include "Compiler/Optimizer/OCLBIUtils.h"
12 #include "Compiler/IGCPassSupport.h"
13 #include "common/LLVMWarningsPush.hpp"
14 #include <llvm/IR/Function.h>
15 #include <llvm/IR/Instructions.h>
16 #include "common/LLVMWarningsPop.hpp"
17 #include "Probe/Assertion.h"
18 
19 using namespace llvm;
20 using namespace IGC;
21 using namespace IGC::IGCMD;
22 
23 // Register pass to igc-opt
24 #define PASS_FLAG "igc-image-func-resolution"
25 #define PASS_DESCRIPTION "Resolves image height, width, depth functions"
26 #define PASS_CFG_ONLY false
27 #define PASS_ANALYSIS false
28 IGC_INITIALIZE_PASS_BEGIN(ImageFuncResolution, PASS_FLAG, PASS_DESCRIPTION, PASS_CFG_ONLY, PASS_ANALYSIS)
29 IGC_INITIALIZE_PASS_DEPENDENCY(MetaDataUtilsWrapper)
30 IGC_INITIALIZE_PASS_DEPENDENCY(CodeGenContextWrapper)
31 IGC_INITIALIZE_PASS_END(ImageFuncResolution, PASS_FLAG, PASS_DESCRIPTION, PASS_CFG_ONLY, PASS_ANALYSIS)
32 
33 char ImageFuncResolution::ID = 0;
34 
ImageFuncResolution()35 ImageFuncResolution::ImageFuncResolution() : FunctionPass(ID), m_implicitArgs()
36 {
37     initializeImageFuncResolutionPass(*PassRegistry::getPassRegistry());
38 }
39 
runOnFunction(Function & F)40 bool ImageFuncResolution::runOnFunction(Function& F) {
41     const MetaDataUtils* pMdUtils = getAnalysis<MetaDataUtilsWrapper>().getMetaDataUtils();
42     m_implicitArgs = ImplicitArgs(F, pMdUtils);
43     m_changed = false;
44     visit(F);
45     return m_changed;
46 }
47 
visitCallInst(CallInst & CI)48 void ImageFuncResolution::visitCallInst(CallInst& CI)
49 {
50     if (!CI.getCalledFunction())
51     {
52         return;
53     }
54 
55     Value* imageRes = nullptr;
56 
57     // Add appropriate sequence and image dimension func
58     StringRef funcName = CI.getCalledFunction()->getName();
59 
60     if (funcName.equals(ImageFuncsAnalysis::GET_IMAGE_HEIGHT))
61     {
62         imageRes = getImageHeight(CI);
63     }
64     else if (funcName.equals(ImageFuncsAnalysis::GET_IMAGE_WIDTH))
65     {
66         imageRes = getImageWidth(CI);
67     }
68     else if (funcName.equals(ImageFuncsAnalysis::GET_IMAGE_DEPTH))
69     {
70         imageRes = getImageDepth(CI);
71     }
72     else if (funcName.equals(ImageFuncsAnalysis::GET_IMAGE_NUM_MIP_LEVELS))
73     {
74         imageRes = getImageNumMipLevels(CI);
75     }
76     else if (funcName.equals(ImageFuncsAnalysis::GET_IMAGE_CHANNEL_DATA_TYPE))
77     {
78         imageRes = getImageChannelDataType(CI);
79     }
80     else if (funcName.equals(ImageFuncsAnalysis::GET_IMAGE_CHANNEL_ORDER))
81     {
82         imageRes = getImageChannelOrder(CI);
83     }
84     else if (funcName.equals(ImageFuncsAnalysis::GET_IMAGE_SRGB_CHANNEL_ORDER))
85     {
86         imageRes = getImplicitImageArg(CI, ImplicitArg::IMAGE_SRGB_CHANNEL_ORDER);
87     }
88     else if (funcName.equals(ImageFuncsAnalysis::GET_IMAGE_ARRAY_SIZE))
89     {
90         imageRes = getImageArraySize(CI);
91     }
92     else if (funcName.equals(ImageFuncsAnalysis::GET_IMAGE_NUM_SAMPLES))
93     {
94         imageRes = getImageNumSamples(CI);
95     }
96     else if (funcName.equals(ImageFuncsAnalysis::GET_SAMPLER_ADDRESS_MODE))
97     {
98         imageRes = getSamplerAddressMode(CI);
99     }
100     else if (funcName.equals(ImageFuncsAnalysis::GET_SAMPLER_NORMALIZED_COORDS))
101     {
102         imageRes = getSamplerNormalizedCoords(CI);
103     }
104     else if (funcName.equals(ImageFuncsAnalysis::GET_SAMPLER_SNAP_WA_REQUIRED))
105     {
106         imageRes = getSamplerSnapWARequired(CI);
107     }
108     else if (funcName.equals(ImageFuncsAnalysis::GET_FLAT_IMAGE_BASEOFFSET))
109     {
110         imageRes = getImplicitImageArg(CI, ImplicitArg::FLAT_IMAGE_BASEOFFSET);
111     }
112     else if (funcName.equals(ImageFuncsAnalysis::GET_FLAT_IMAGE_HEIGHT))
113     {
114         imageRes = getImplicitImageArg(CI, ImplicitArg::FLAT_IMAGE_HEIGHT);
115     }
116     else if (funcName.equals(ImageFuncsAnalysis::GET_FLAT_IMAGE_WIDTH))
117     {
118         imageRes = getImplicitImageArg(CI, ImplicitArg::FLAT_IMAGE_WIDTH);
119     }
120     else if (funcName.equals(ImageFuncsAnalysis::GET_FLAT_IMAGE_PITCH))
121     {
122         imageRes = getImplicitImageArg(CI, ImplicitArg::FLAT_IMAGE_PITCH);
123     }
124     else
125     {
126         // Non image function, do nothing
127         return;
128     }
129 
130     // Replace original image dim call instruction by the result of the appropriate sequence
131     CI.replaceAllUsesWith(imageRes);
132     CI.eraseFromParent();
133     m_changed = true;
134 }
135 
getImageHeight(CallInst & CI)136 Value* ImageFuncResolution::getImageHeight(CallInst& CI)
137 {
138     Argument* arg = getImplicitImageArg(CI, ImplicitArg::IMAGE_HEIGHT);
139     return arg;
140 }
141 
getImageWidth(CallInst & CI)142 Value* ImageFuncResolution::getImageWidth(CallInst& CI)
143 {
144     Argument* arg = getImplicitImageArg(CI, ImplicitArg::IMAGE_WIDTH);
145     return arg;
146 }
147 
getImageDepth(CallInst & CI)148 Value* ImageFuncResolution::getImageDepth(CallInst& CI)
149 {
150     Argument* arg = getImplicitImageArg(CI, ImplicitArg::IMAGE_DEPTH);
151     return arg;
152 }
153 
getImageNumMipLevels(CallInst & CI)154 Value* ImageFuncResolution::getImageNumMipLevels(CallInst& CI)
155 {
156     Argument* arg = getImplicitImageArg(CI, ImplicitArg::IMAGE_NUM_MIP_LEVELS);
157     return arg;
158 }
159 
getImageChannelDataType(CallInst & CI)160 Value* ImageFuncResolution::getImageChannelDataType(CallInst& CI)
161 {
162     Argument* arg = getImplicitImageArg(CI, ImplicitArg::IMAGE_CHANNEL_DATA_TYPE);
163     return arg;
164 }
165 
getImageChannelOrder(CallInst & CI)166 Value* ImageFuncResolution::getImageChannelOrder(CallInst& CI)
167 {
168     Argument* arg = getImplicitImageArg(CI, ImplicitArg::IMAGE_CHANNEL_ORDER);
169     return arg;
170 }
171 
getImageArraySize(CallInst & CI)172 Value* ImageFuncResolution::getImageArraySize(CallInst& CI)
173 {
174     Argument* arg = getImplicitImageArg(CI, ImplicitArg::IMAGE_ARRAY_SIZE);
175     return arg;
176 }
177 
getImageNumSamples(CallInst & CI)178 Value* ImageFuncResolution::getImageNumSamples(CallInst& CI)
179 {
180     Argument* arg = getImplicitImageArg(CI, ImplicitArg::IMAGE_NUM_SAMPLES);
181     return arg;
182 }
183 
getSamplerAddressMode(CallInst & CI)184 Value* ImageFuncResolution::getSamplerAddressMode(CallInst& CI)
185 {
186     MetaDataUtils* pMdUtils = getAnalysis<MetaDataUtilsWrapper>().getMetaDataUtils();
187     ModuleMetaData* modMD = getAnalysis<MetaDataUtilsWrapper>().getModuleMetaData();
188 
189     Value* sampler = ValueTracker::track(&CI, 0, pMdUtils, modMD);
190     IGC_ASSERT_MESSAGE(sampler != nullptr, "Sampler untraceable for ImplicitArg::SAMPLER_ADDRESS");
191     if (isa<Argument>(sampler))
192     {
193         Argument* arg = getImplicitImageArg(CI, ImplicitArg::SAMPLER_ADDRESS);
194         return arg;
195     }
196     else
197     {
198         llvm::Function* pFunc = CI.getParent()->getParent();
199 
200         IGC_ASSERT_MESSAGE(isa<ConstantInt>(sampler), "Sampler must be a constant integer");
201         InlineSamplerState samplerStateAddressMode{ cast<ConstantInt>(sampler)->getZExtValue() };
202         uint64_t samplerVal = 0;
203         uint samplerValue = int_cast<unsigned int>(cast<ConstantInt>(sampler)->getZExtValue());
204         if (modMD->FuncMD.find(pFunc) != modMD->FuncMD.end())
205         {
206             FunctionMetaData funcMD = modMD->FuncMD[pFunc];
207             ResourceAllocMD resAllocMD = funcMD.resAllocMD;
208             for (auto i = resAllocMD.inlineSamplersMD.begin(), e = resAllocMD.inlineSamplersMD.end(); i != e; i++)
209             {
210                 IGC::InlineSamplersMD inlineSamplerMD = *i;
211                 if (samplerValue == inlineSamplerMD.m_Value)
212                 {
213                     InlineSamplerState samplerState{ static_cast<uint64_t>(samplerValue) };
214                     samplerVal = inlineSamplerMD.addressMode;
215                 }
216             }
217         }
218         return ConstantInt::get(CI.getType(), samplerVal);
219     }
220 }
221 
getSamplerNormalizedCoords(CallInst & CI)222 Value* ImageFuncResolution::getSamplerNormalizedCoords(CallInst& CI)
223 {
224     MetaDataUtils* pMdUtils = getAnalysis<MetaDataUtilsWrapper>().getMetaDataUtils();
225     ModuleMetaData* modMD = getAnalysis<MetaDataUtilsWrapper>().getModuleMetaData();
226     Value* sampler = ValueTracker::track(&CI, 0, pMdUtils, modMD);
227     if (sampler == nullptr)
228     {
229         // TODO: For now disable WA if unable to trace sampler argument.
230         // Will need to rework WA to add support for indirect sampler case.
231         return ConstantInt::get(CI.getType(), 0);
232     }
233     else if (isa<Argument>(sampler))
234     {
235         Argument* arg = getImplicitImageArg(CI, ImplicitArg::SAMPLER_NORMALIZED);
236         return arg;
237     }
238     else
239     {
240         llvm::Function* pFunc = CI.getParent()->getParent();
241         IGC_ASSERT_MESSAGE(isa<ConstantInt>(sampler), "Sampler must be a constant integer");
242 
243         uint64_t samplerVal = 0;
244         uint samplerValue = int_cast<unsigned int>(cast<ConstantInt>(sampler)->getZExtValue());
245 
246         if (modMD->FuncMD.find(pFunc) != modMD->FuncMD.end())
247         {
248             FunctionMetaData funcMD = modMD->FuncMD[pFunc];
249             ResourceAllocMD resAllocMD = funcMD.resAllocMD;
250             for (auto i = resAllocMD.inlineSamplersMD.begin(), e = resAllocMD.inlineSamplersMD.end(); i != e; ++i)
251             {
252                 IGC::InlineSamplersMD inlineSamplerMD = *i;
253                 if (samplerValue == inlineSamplerMD.m_Value)
254                 {
255                     InlineSamplerState samplerState{ static_cast<uint64_t>(samplerValue) };
256                     samplerVal = inlineSamplerMD.NormalizedCoords;
257                 }
258             }
259         }
260         return ConstantInt::get(CI.getType(), samplerVal);
261     }
262 }
263 
getSamplerSnapWARequired(CallInst & CI)264 Value* ImageFuncResolution::getSamplerSnapWARequired(CallInst& CI)
265 {
266     MetaDataUtils* pMdUtils = getAnalysis<MetaDataUtilsWrapper>().getMetaDataUtils();
267     ModuleMetaData* modMD = getAnalysis<MetaDataUtilsWrapper>().getModuleMetaData();
268     Value* sampler = ValueTracker::track(&CI, 0, pMdUtils, modMD);
269     if (sampler == nullptr)
270     {
271         // TODO: For now disable WA if unable to trace sampler argument.
272         // Will need to rework WA to add support for indirect sampler case.
273         return ConstantInt::get(CI.getType(), 0);
274     }
275     else if (isa<Argument>(sampler))
276     {
277         Argument* arg = getImplicitImageArg(CI, ImplicitArg::SAMPLER_SNAP_WA);
278         return arg;
279     }
280     else
281     {
282         IGC_ASSERT_MESSAGE(isa<ConstantInt>(sampler), "Sampler must be a constant integer");
283 
284         llvm::Function* pFunc = CI.getParent()->getParent();
285 
286         bool snapWARequired = false;
287         uint samplerVal = int_cast<unsigned int>(cast<ConstantInt>(sampler)->getZExtValue());
288 
289         if (modMD->FuncMD.find(pFunc) != modMD->FuncMD.end())
290         {
291             FunctionMetaData funcMD = modMD->FuncMD[pFunc];
292             ResourceAllocMD resAllocMD = funcMD.resAllocMD;
293             for (auto i = resAllocMD.inlineSamplersMD.begin(), e = resAllocMD.inlineSamplersMD.end(); i != e; ++i)
294             {
295                 InlineSamplersMD inlineSamplerMD = *i;
296                 if (samplerVal == inlineSamplerMD.m_Value)
297                 {
298                     InlineSamplerState samplerState{ static_cast<uint64_t>(samplerVal) };
299                     bool anyAddressModeClamp =
300                         inlineSamplerMD.TCXAddressMode == iOpenCL::SAMPLER_TEXTURE_ADDRESS_MODE_BORDER ||
301                         inlineSamplerMD.TCYAddressMode == iOpenCL::SAMPLER_TEXTURE_ADDRESS_MODE_BORDER ||
302                         inlineSamplerMD.TCZAddressMode == iOpenCL::SAMPLER_TEXTURE_ADDRESS_MODE_BORDER;
303                     bool anyMapFilterModeNearest =
304                         inlineSamplerMD.MagFilterType == iOpenCL::SAMPLER_MAPFILTER_POINT ||
305                         inlineSamplerMD.MinFilterType == iOpenCL::SAMPLER_MAPFILTER_POINT;
306                     snapWARequired = anyAddressModeClamp &&
307                         anyMapFilterModeNearest &&
308                         !inlineSamplerMD.NormalizedCoords;
309                 }
310             }
311         }
312         return ConstantInt::get(CI.getType(), snapWARequired ? -1 : 0);
313     }
314 }
315 
getImplicitImageArg(CallInst & CI,ImplicitArg::ArgType argType)316 Argument* ImageFuncResolution::getImplicitImageArg(CallInst& CI, ImplicitArg::ArgType argType) {
317     // Only images that are arguments are supported!
318     Argument* image = cast<Argument>(ValueTracker::track(&CI, 0));
319 
320     unsigned int numImplicitArgs = m_implicitArgs.size();
321     unsigned int implicitArgIndex = m_implicitArgs.getImageArgIndex(argType, image);
322 
323     Function* pFunc = CI.getParent()->getParent();
324     IGC_ASSERT_MESSAGE(pFunc->arg_size() >= numImplicitArgs, "Function arg size does not match meta data args.");
325     unsigned int implicitArgIndexInFunc = pFunc->arg_size() - numImplicitArgs + implicitArgIndex;
326 
327     Function::arg_iterator arg = pFunc->arg_begin();
328     for (unsigned int i = 0; i < implicitArgIndexInFunc; ++i, ++arg);
329 
330     return &(*arg);
331 }
332