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 #pragma once
10 
11 #include "Compiler/CodeGenPublic.h"
12 #include "Compiler/MetaDataApi/MetaDataApi.h"
13 #include "Compiler/Optimizer/ValueTracker.h"
14 #include "common/LLVMWarningsPush.hpp"
15 #include <llvm/ADT/MapVector.h>
16 #include <llvm/ADT/StringRef.h>
17 #include <llvmWrapper/IR/Intrinsics.h>
18 #include "common/LLVMWarningsPop.hpp"
19 #include "GenISAIntrinsics/GenIntrinsics.h"
20 #include <map>
21 #include "Probe/Assertion.h"
22 
23 namespace llvm
24 {
25     class CallInst;
26 }
27 
28 namespace IGC
29 {
30     class CCommand
31     {
32     public:
33         /// @brief  gets llvm function declaration for GenISA_ISA Intrinsic
34         /// @param  Id          the wanted GenISA_ISA intrinsic
35         /// @param  ptrTy       for intrinsic with overloaded types.
36         /// @returns    llvm Function
37         llvm::Function* getFunctionDeclaration(llvm::GenISAIntrinsic::ID id, llvm::ArrayRef<llvm::Type*> Tys = llvm::None);
38 
39         /// @brief  gets llvm function declaration for LLVM Intrinsic
40         /// @param  Id          the wanted LLVM intrinsic
41         /// @param  ptrTy       for intrinsic with overloaded types.
42         /// @returns    llvm Function
43         llvm::Function* getFunctionDeclaration(IGCLLVM::Intrinsic id, llvm::ArrayRef<llvm::Type*> Tys = llvm::None);
44 
45         /// @brief  Creates llvm function call for LLVM Intrinsic and replace the
46         ///         current instruction with the new function call.
47         /// @param  Id          the wanted LLVM intrinsic
48         /// @param  ptrTy       for intrinsic with overloaded types.
49         void replaceCallInst(IGCLLVM::Intrinsic intrinsicName, llvm::ArrayRef<llvm::Type*> Tys = llvm::None);
50 
51 
52         /// @brief  Creates llvm function call for GenISA_ISA Intrinsic and replace the
53         ///         current instruction with the new function call.
54         /// @param  Id          the wanted GenISA_ISA intrinsic
55         /// @param  ptrTy       for intrinsic with overloaded types.
56         void replaceGenISACallInst(llvm::GenISAIntrinsic::ID intrinsicName, llvm::ArrayRef<llvm::Type*> Tys = llvm::None);
57 
58         /// @brief  reap init() and createIntrinsic().
59         /// @param  Inst            the call instruction that need to be replaced.
60         /// @param  CodeGenContext  context to return errors
61         void execute(llvm::CallInst* Inst, IGC::CodeGenContext* CodeGenContext);
62 
63         /// @brief  replace the old __builtin_IB function call with the match llvm/GenISA_ISA
64         ///         instructions.
65         /// @param  Inst        the call instruction that need to be replaced.
66         virtual void createIntrinsic() = 0;
67 
68         /// @brief  verify that there are no user errors
verifyCommand()69         virtual void verifyCommand() {}
70 
71         /// @brief  initialize the callInst,  function, context, constants and clear the arg list.
72         /// @param  Inst            the call instruction that need to be replaced.
73         /// @param  CodeGenContext  context to return errors
74         void init(llvm::CallInst* Inst, IGC::CodeGenContext* CodeGenContext);
75         void clearArgsList(void);
76 
77         enum CoordType
78         {
79             FloatType,
80             IntType
81         };
82 
CCommand(void)83         CCommand(void) :
84             m_pFloatZero(nullptr),
85             m_pIntZero(nullptr),
86             m_pIntOne(nullptr),
87             m_pCallInst(nullptr),
88             m_pFunc(nullptr),
89             m_pCtx(nullptr),
90             m_pCodeGenContext(nullptr),
91             m_pFloatType(nullptr),
92             m_pIntType(nullptr)
93         {}
~CCommand(void)94         virtual ~CCommand(void) {};
95 
96     protected:
97         llvm::Value* m_pFloatZero;
98         llvm::Value* m_pIntZero;
99         llvm::Value* m_pIntOne;
100         llvm::CallInst* m_pCallInst;
101         llvm::Function* m_pFunc;
102         llvm::LLVMContext* m_pCtx;
103         IGC::CodeGenContext* m_pCodeGenContext;
104         llvm::SmallVector<llvm::Value*, 10> m_args;
105         llvm::DebugLoc m_DL;
106         llvm::Type* m_pFloatType;
107         llvm::IntegerType* m_pIntType;
108     };
109 
ResourceTypeMap(ResourceTypeEnum type)110     static inline BufferType ResourceTypeMap(ResourceTypeEnum type)
111     {
112         switch (type)
113         {
114         case IGC::UAVResourceType:
115             return UAV;
116         case IGC::BindlessUAVResourceType:
117             return BINDLESS;
118         case IGC::SRVResourceType:
119             return RESOURCE;
120         case IGC::SamplerResourceType:
121             return SAMPLER;
122         case IGC::BindlessSamplerResourceType:
123             return BINDLESS_SAMPLER;
124         case IGC::OtherResourceType:
125             return BUFFER_TYPE_UNKNOWN;
126         default:
127             IGC_ASSERT_MESSAGE(0, "unknown type!");
128             return BUFFER_TYPE_UNKNOWN;
129         }
130     };
131 
132     class CImagesBI : public CCommand
133     {
134     public:
135         enum Dimension
136         {
137             DIM_1D,
138             DIM_1D_ARRAY,
139             DIM_2D,
140             DIM_2D_ARRAY,
141             DIM_3D
142         };
143 
144         enum CoordComponents
145         {
146             COORD_X,
147             COORD_Y,
148             COORD_Z,
149             COORD_W
150         };
151 
152         struct ParamInfo
153         {
ParamInfoParamInfo154             ParamInfo(int i, ResourceTypeEnum t, ResourceExtensionTypeEnum extension) :
155                 index(i), type(ResourceTypeMap(t)), extension(extension) {}
ParamInfoParamInfo156             ParamInfo() :
157                 index(0), type(BUFFER_TYPE_UNKNOWN), extension(NonExtensionType) {}
158 
159             int index;
160             BufferType type;
161             ResourceExtensionTypeEnum extension;
162         };
163 
164         typedef llvm::MapVector<llvm::Value*, ParamInfo> ParamMap;
165         typedef std::map<int, int> InlineMap;
166 
167         class CImagesUtils
168         {
169         public:
170             /// @brief  find the BTI of the image argumant
171             /// @param  paramIndex  the index of the image paramtere in the call isntruciton
172             /// @returns  the image index
173             static llvm::ConstantInt* getImageIndex(ParamMap* pParamMap, llvm::CallInst* pCallInst, unsigned int paramIndex, llvm::Argument*& imageParam);
174 
175             /// @brief  find the type (UAV/RESOURCE) of the image argumant
176             /// @returns  the image type
177             static BufferType getImageType(ParamMap* pParamMap, llvm::CallInst* pCallInst, unsigned int paramIndex);
178 
179             /// @brief  find the image argument associated with the given bufType and idx
180             /// @returns the image argument
181             static llvm::Argument* findImageFromBufferPtr(const IGC::IGCMD::MetaDataUtils& MdUtils, llvm::Function* F, BufferType bufType, uint64_t idx, const IGC::ModuleMetaData* modMD);
182         };
183 
CImagesBI(ParamMap * paramMap,InlineMap * inlineMap,int * nextSampler,Dimension Dim)184         CImagesBI(ParamMap* paramMap, InlineMap* inlineMap, int* nextSampler, Dimension Dim) :
185             m_pParamMap(paramMap), m_pInlineMap(inlineMap), m_pNextSampler(nextSampler), m_dim(Dim),
186             CoordX(nullptr), CoordY(nullptr), CoordZ(nullptr), m_IncorrectBti(false) {}
187 
188         /// @brief  push 3 zeros offset to the function argumant list
189         void prepareZeroOffsets(void);
190 
191         /// @brief  initilaize CoordX/Y/Z with the given coordinates.
192         /// @param  Dim         the image dimension
193         /// @param  Coord       the coords from the original intrinsic.
194         /// @param  Zero        const zero with the correct type (i.e. float or int)
195         ///                     it been use only for image_1d and image_2d
196         void prepareCoords(Dimension Dim, llvm::Value* Coord, llvm::Value* Zero);
197 
198         /// @brief  push the colors to the function argument list
199         /// @param  Color       the Color value
200         void prepareColor(llvm::Value* Color);
201 
202         /// @brief  set LOD to Zero and push the function argument list
203         /// @param  Coord       the type of zero (int or float)
204         void prepareLOD(CoordType Coord);
205 
206 
207         /// @brief  push the sampler index into the function argument list
208         void prepareSamplerIndex(void);
209 
210         /// @brief  create a call to the GetBufferPtr intrinsic pseudo-instruction
211         /// @brief  push the image index into the function argument list
212         void createGetBufferPtr(void);
213 
214         /// @brief  returns "true" if the "val" is integer or float with fractional part = 0.
215         static bool derivedFromInt(const llvm::Value* pVal);
216 
217         void verifyCommand();
218 
219     protected:
220         /// @brief  push the image index into the function argument list
221         void prepareImageBTI(void);
222 
223         // m_pParamMap - maps image and sampler kernel parameters to BTIs
224         //               and sampler array indexes, respecitvely
225         ParamMap* m_pParamMap;
226 
227         // m_pInlineMap - maps inline sampler values (CLK_...) to sampler
228         //                array indexes.
229         InlineMap* m_pInlineMap;
230 
231         // The next sampler index to allocate a newly encountered
232         // inline sampler
233         int* m_pNextSampler;
234 
235         Dimension m_dim;
236         llvm::Value* CoordX;
237         llvm::Value* CoordY;
238         llvm::Value* CoordZ;
239         bool m_IncorrectBti;
240     };
241 
242     class CBuiltinsResolver
243     {
244     private:
245         std::map<llvm::StringRef, std::unique_ptr<CCommand>> m_CommandMap;
246 
247         // the list of known builtins not to be resolved
248         std::vector<llvm::StringRef> m_KnownBuiltins;
249         CodeGenContext* m_CodeGenContext;
250     public:
251         CBuiltinsResolver(CImagesBI::ParamMap* paramMap, CImagesBI::InlineMap* inlineMap, int* nextSampler, CodeGenContext* ctx);
~CBuiltinsResolver(void)252         ~CBuiltinsResolver(void) {}
253 
254         // resolve __builtin_IB_* calls.
255         // return values:
256         //              true - when CallInst was __builtin_IB_* and successfully repleced
257         //              false - when CallInst wasn't __builtin_IB*
258         bool resolveBI(llvm::CallInst* Inst);
259     };
260 
261     union InlineSamplerState
262     {
263         struct _state
264         {
265             uint64_t TCXAddressMode : 3;
266             uint64_t TCYAddressMode : 3;
267             uint64_t TCZAddressMode : 3;
268             uint64_t MagFilterMode : 2;
269             uint64_t MinFilterMode : 2;
270             uint64_t MipFilterMode : 2;
271             uint64_t NormalizedCoords : 1;
272             uint64_t CompareFunction : 4;
273             uint64_t _reserved : 44;
274         } state;
275         uint64_t _Value;
276 
InlineSamplerState()277         InlineSamplerState() : _Value(0) {}
InlineSamplerState(uint64_t samplerValue)278         InlineSamplerState(uint64_t samplerValue) : _Value(samplerValue) {}
279 
280         enum ADDRESS_MODE
281         {
282             ADDRESS_MODE_WRAP,
283             ADDRESS_MODE_CLAMP,
284             ADDRESS_MODE_MIRROR,
285             ADDRESS_MODE_BORDER,
286             ADDRESS_MODE_MIRRORONCE,
287             ADDRESS_MODE_MIRROR101,
288             NUM_ADDRESS_MODE
289         };
290 
291         enum MAP_FILTER_MODE    // Applies for MagFilterMode and MinFilterMode
292         {
293             MAP_FILTER_MODE_POINT,
294             MAP_FILTER_MODE_LINEAR,
295             MAP_FILTER_MODE_ANISOTROPIC,
296             MAP_FILTER_MODE_GAUSSIANQUAD,
297             MAP_FILTER_MODE_PYRAMIDALQUAD,
298             MAP_FILTER_MODE_MONO,
299             NUM_MAP_FILTER_MODE
300         };
301 
302         enum MIP_FILTER_MODE
303         {
304             MIP_FILTER_MODE_POINT,
305             MIP_FILTER_MODE_LINEAR,
306             MIP_FILTER_MODE_NONE,
307             NUM_MIP_FILTER_MODE
308         };
309 
310         enum NORMALIZED_MODE
311         {
312             NORMALIZED_MODE_FALSE,
313             NORMALIZED_MODE_TRUE,
314         };
315 
316         enum COMPARE_FUNC
317         {
318             COMPARE_FUNC_NONE,
319             COMPARE_FUNC_LESS,
320             COMPARE_FUNC_LESS_EQUAL = 2,
321             COMPARE_FUNC_GREATER = 3,
322             COMPARE_FUNC_GREATER_EQUAL = 4,
323             COMPARE_FUNC_EQUAL = 5,
324             COMPARE_FUNC_NOT_EQUAL = 6,
325             COMPARE_FUNC_ALWAYS = 7,
326             COMPARE_FUNC_NEVER = 8,
327             NUM_COMPARE_FUNC
328         };
329     };
330 
331     // Built-in image functions
332     // These values need to match the runtime equivalent
333 #define LEGACY_CLK_ADDRESS_NONE                         0x00
334 #define LEGACY_CLK_ADDRESS_CLAMP                        0x01
335 #define LEGACY_CLK_ADDRESS_CLAMP_TO_EDGE                0x02
336 #define LEGACY_CLK_ADDRESS_REPEAT                       0x03
337 #define LEGACY_CLK_ADDRESS_MIRRORED_REPEAT              0x04
338 #define LEGACY_CLK_ADDRESS_MIRRORED_REPEAT_101_INTEL     0x05
339 
340 #define LEGACY_CLK_NORMALIZED_COORDS_FALSE   0x00
341 #define LEGACY_CLK_NORMALIZED_COORDS_TRUE    0x08
342 
343 #define LEGACY_CLK_FILTER_NEAREST            0x00
344 #define LEGACY_CLK_FILTER_LINEAR             0x10
345 
346     // Mask values for the various components
347 #define LEGACY_SAMPLER_ADDRESS_MASK          0x07
348 #define LEGACY_SAMPLER_NORMALIZED_MASK       0x08
349 #define LEGACY_SAMPLER_FILTER_MASK           0x10
350 
351     // These values need to match SPIR sampler enum
352 #define SPIR_CLK_ADDRESS_NONE                       0x00
353 #define SPIR_CLK_ADDRESS_CLAMP_TO_EDGE              0x02
354 #define SPIR_CLK_ADDRESS_CLAMP                        0x04
355 #define SPIR_CLK_ADDRESS_REPEAT                     0x06
356 #define SPIR_CLK_ADDRESS_MIRRORED_REPEAT            0x08
357 #define SPIR_CLK_ADDRESS_MIRRORED_REPEAT_101_INTEL     0x0A
358 
359 #define SPIR_CLK_NORMALIZED_COORDS_FALSE   0x00
360 #define SPIR_CLK_NORMALIZED_COORDS_TRUE    0x01
361 
362 #define SPIR_CLK_FILTER_NEAREST            0x0010
363 #define SPIR_CLK_FILTER_LINEAR             0x0020
364 
365     // Mask values for the various components
366 #define SPIR_SAMPLER_NORMALIZED_MASK       0x01
367 #define SPIR_SAMPLER_ADDRESS_MASK          0x0e
368 #define SPIR_SAMPLER_FILTER_MASK           0x30
369 
370 } // namespace IGC
371