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