1 //===- OCLUtil.cpp - OCL Utilities ----------------------------------------===//
2 //
3 // The LLVM/SPIRV Translator
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved.
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a
11 // copy of this software and associated documentation files (the "Software"),
12 // to deal with the Software without restriction, including without limitation
13 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 // and/or sell copies of the Software, and to permit persons to whom the
15 // Software is furnished to do so, subject to the following conditions:
16 //
17 // Redistributions of source code must retain the above copyright notice,
18 // this list of conditions and the following disclaimers.
19 // Redistributions in binary form must reproduce the above copyright notice,
20 // this list of conditions and the following disclaimers in the documentation
21 // and/or other materials provided with the distribution.
22 // Neither the names of Advanced Micro Devices, Inc., nor the names of its
23 // contributors may be used to endorse or promote products derived from this
24 // Software without specific prior written permission.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
31 // THE SOFTWARE.
32 //
33 //===----------------------------------------------------------------------===//
34 //
35 // This file implements OCL utility functions.
36 //
37 //===----------------------------------------------------------------------===//
38 #define DEBUG_TYPE "oclutil"
39
40 #include "SPIRVInternal.h"
41 #include "OCLUtil.h"
42 #include "SPIRVEntry.h"
43 #include "SPIRVFunction.h"
44 #include "SPIRVInstruction.h"
45 #include "llvm/ADT/StringSwitch.h"
46 #include "llvm/IR/InstVisitor.h"
47 #include "llvm/IR/Instructions.h"
48 #include "llvm/IR/IRBuilder.h"
49 #include "llvm/IR/Verifier.h"
50 #include "llvm/Pass.h"
51 #include "llvm/PassSupport.h"
52 #include "llvm/Support/CommandLine.h"
53 #include "llvm/Support/Debug.h"
54 #include "llvm/Support/raw_ostream.h"
55
56 using namespace llvm;
57 using namespace SPIRV;
58
59 namespace OCLUtil {
60
61
62 #ifndef SPIRV_OCL_SPECIAL_TYPES_DEFAULT_ADDR_SPACE
63 #define SPIRV_OCL_SPECIAL_TYPES_DEFAULT_ADDR_SPACE SPIRAS_Private
64 #endif
65
66 #ifndef SPIRV_QUEUE_T_ADDR_SPACE
67 #define SPIRV_QUEUE_T_ADDR_SPACE SPIRV_OCL_SPECIAL_TYPES_DEFAULT_ADDR_SPACE
68 #endif
69
70 #ifndef SPIRV_EVENT_T_ADDR_SPACE
71 #define SPIRV_EVENT_T_ADDR_SPACE SPIRV_OCL_SPECIAL_TYPES_DEFAULT_ADDR_SPACE
72 #endif
73
74 #ifndef SPIRV_CLK_EVENT_T_ADDR_SPACE
75 #define SPIRV_CLK_EVENT_T_ADDR_SPACE SPIRV_OCL_SPECIAL_TYPES_DEFAULT_ADDR_SPACE
76 #endif
77
78 #ifndef SPIRV_RESERVE_ID_T_ADDR_SPACE
79 #define SPIRV_RESERVE_ID_T_ADDR_SPACE SPIRV_OCL_SPECIAL_TYPES_DEFAULT_ADDR_SPACE
80 #endif
81 // Excerpt from SPIR 2.0 spec.:
82 // Pipe objects are represented using pointers to the opaque %opencl.pipe LLVM structure type
83 // which reside in the global address space.
84 #ifndef SPIRV_PIPE_ADDR_SPACE
85 #define SPIRV_PIPE_ADDR_SPACE SPIRAS_Global
86 #endif
87 // Excerpt from SPIR 2.0 spec.:
88 // Note: Images data types reside in global memory and hence should be marked as such in the
89 // "kernel arg addr space" metadata.
90 #ifndef SPIRV_IMAGE_ADDR_SPACE
91 #define SPIRV_IMAGE_ADDR_SPACE SPIRAS_Global
92 #endif
93
94 ///////////////////////////////////////////////////////////////////////////////
95 //
96 // Functions for getting builtin call info
97 //
98 ///////////////////////////////////////////////////////////////////////////////
getAtomicWorkItemFenceLiterals(CallInst * CI)99 AtomicWorkItemFenceLiterals getAtomicWorkItemFenceLiterals(CallInst* CI) {
100 return std::make_tuple(getArgAsInt(CI, 0),
101 static_cast<OCLMemOrderKind>(getArgAsInt(CI, 1)),
102 static_cast<OCLScopeKind>(getArgAsInt(CI, 2)));
103 }
104
getAtomicBuiltinNumMemoryOrderArgs(StringRef Name)105 size_t getAtomicBuiltinNumMemoryOrderArgs(StringRef Name) {
106 if (Name.startswith("atomic_compare_exchange"))
107 return 2;
108 return 1;
109 }
110
getBarrierLiterals(CallInst * CI)111 BarrierLiterals getBarrierLiterals(CallInst* CI){
112 auto N = CI->getNumArgOperands();
113 assert (N == 1 || N == 2);
114
115 std::string DemangledName;
116 if (!oclIsBuiltin(CI->getCalledFunction()->getName(), &DemangledName)) {
117 assert(0 && "call must a builtin (work_group_barrier or sub_group_barrier)");
118 }
119
120 OCLScopeKind scope = OCLMS_work_group;
121 if (DemangledName == kOCLBuiltinName::SubGroupBarrier) {
122 scope = OCLMS_sub_group;
123 }
124
125 return std::make_tuple(getArgAsInt(CI, 0),
126 N == 1 ? OCLMS_work_group : static_cast<OCLScopeKind>(getArgAsInt(CI, 1)),
127 scope);
128 }
129
130 unsigned
getExtOp(StringRef OrigName,const std::string & GivenDemangledName)131 getExtOp(StringRef OrigName, const std::string &GivenDemangledName) {
132 std::string DemangledName = GivenDemangledName;
133 if (!oclIsBuiltin(OrigName, DemangledName.empty() ? &DemangledName : nullptr))
134 return ~0U;
135 DEBUG(dbgs() << "getExtOp: demangled name: " << DemangledName << '\n');
136 OCLExtOpKind EOC;
137 bool Found = OCLExtOpMap::rfind(DemangledName, &EOC);
138 if (!Found) {
139 std::string Prefix;
140 switch (LastFuncParamType(OrigName)) {
141 case ParamType::UNSIGNED:
142 Prefix = "u_";
143 break;
144 case ParamType::SIGNED:
145 Prefix = "s_";
146 break;
147 case ParamType::FLOAT:
148 Prefix = "f";
149 break;
150 default:
151 llvm_unreachable("unknown mangling!");
152 }
153 Found = OCLExtOpMap::rfind(Prefix + DemangledName, &EOC);
154 }
155 if (Found)
156 return EOC;
157 else
158 return ~0U;
159 }
160
161 std::unique_ptr<SPIRVEntry>
getSPIRVInst(const OCLBuiltinTransInfo & Info)162 getSPIRVInst(const OCLBuiltinTransInfo &Info) {
163 Op OC = OpNop;
164 unsigned ExtOp = ~0U;
165 SPIRVEntry *Entry = nullptr;
166 if (OCLSPIRVBuiltinMap::find(Info.UniqName, &OC))
167 Entry = SPIRVEntry::create(OC);
168 else if ((ExtOp = getExtOp(Info.MangledName, Info.UniqName)) != ~0U)
169 Entry = static_cast<SPIRVEntry*>(
170 SPIRVEntry::create_unique(SPIRVEIS_OpenCL, ExtOp).get());
171 return std::unique_ptr<SPIRVEntry>(Entry);
172 }
173
174 ///////////////////////////////////////////////////////////////////////////////
175 //
176 // Functions for getting module info
177 //
178 ///////////////////////////////////////////////////////////////////////////////
179
180 unsigned
encodeOCLVer(unsigned short Major,unsigned char Minor,unsigned char Rev)181 encodeOCLVer(unsigned short Major,
182 unsigned char Minor, unsigned char Rev) {
183 return (Major * 100 + Minor) * 1000 + Rev;
184 }
185
186 std::tuple<unsigned short, unsigned char, unsigned char>
decodeOCLVer(unsigned Ver)187 decodeOCLVer(unsigned Ver) {
188 unsigned short Major = Ver / 100000;
189 unsigned char Minor = (Ver % 100000) / 1000;
190 unsigned char Rev = Ver % 1000;
191 return std::make_tuple(Major, Minor, Rev);
192 }
193
getOCLVersion(Module * M,bool AllowMulti)194 unsigned getOCLVersion(Module *M, bool AllowMulti) {
195 NamedMDNode *NamedMD = M->getNamedMetadata(kSPIR2MD::OCLVer);
196 if (!NamedMD)
197 return 0;
198 assert (NamedMD->getNumOperands() > 0 && "Invalid SPIR");
199 if (!AllowMulti && NamedMD->getNumOperands() != 1)
200 report_fatal_error("Multiple OCL version metadata not allowed");
201
202 // If the module was linked with another module, there may be multiple
203 // operands.
204 auto getVer = [=](unsigned I) {
205 auto MD = NamedMD->getOperand(I);
206 return std::make_pair(getMDOperandAsInt(MD, 0), getMDOperandAsInt(MD, 1));
207 };
208 auto Ver = getVer(0);
209 for (unsigned I = 1, E = NamedMD->getNumOperands(); I != E; ++I)
210 if (Ver != getVer(I))
211 report_fatal_error("OCL version mismatch");
212
213 return encodeOCLVer(Ver.first, Ver.second, 0);
214 }
215
216 void
decodeMDNode(MDNode * N,unsigned & X,unsigned & Y,unsigned & Z)217 decodeMDNode(MDNode* N, unsigned& X, unsigned& Y, unsigned& Z) {
218 if (N == NULL)
219 return;
220 X = getMDOperandAsInt(N, 1);
221 Y = getMDOperandAsInt(N, 2);
222 Z = getMDOperandAsInt(N, 3);
223 }
224
225 /// Encode LLVM type by SPIR-V execution mode VecTypeHint
226 unsigned
encodeVecTypeHint(Type * Ty)227 encodeVecTypeHint(Type *Ty){
228 if (Ty->isHalfTy())
229 return 4;
230 if (Ty->isFloatTy())
231 return 5;
232 if (Ty->isDoubleTy())
233 return 6;
234 if (IntegerType* intTy = dyn_cast<IntegerType>(Ty)) {
235 switch (intTy->getIntegerBitWidth()) {
236 case 8:
237 return 0;
238 case 16:
239 return 1;
240 case 32:
241 return 2;
242 case 64:
243 return 3;
244 default:
245 llvm_unreachable("invalid integer type");
246 }
247 }
248 if (VectorType* VecTy = dyn_cast<VectorType>(Ty)) {
249 Type* EleTy = VecTy->getElementType();
250 unsigned Size = VecTy->getVectorNumElements();
251 return Size << 16 | encodeVecTypeHint(EleTy);
252 }
253 llvm_unreachable("invalid type");
254 }
255
256 Type *
decodeVecTypeHint(LLVMContext & C,unsigned code)257 decodeVecTypeHint(LLVMContext &C, unsigned code) {
258 unsigned VecWidth = code >> 16;
259 unsigned Scalar = code & 0xFFFF;
260 Type *ST = nullptr;
261 switch(Scalar) {
262 case 0:
263 case 1:
264 case 2:
265 case 3:
266 ST = IntegerType::get(C, 1 << (3 + Scalar));
267 break;
268 case 4:
269 ST = Type::getHalfTy(C);
270 break;
271 case 5:
272 ST = Type::getFloatTy(C);
273 break;
274 case 6:
275 ST = Type::getDoubleTy(C);
276 break;
277 default:
278 llvm_unreachable("Invalid vec type hint");
279 }
280 if (VecWidth < 1)
281 return ST;
282 return VectorType::get(ST, VecWidth);
283 }
284
285 unsigned
transVecTypeHint(MDNode * Node)286 transVecTypeHint(MDNode* Node) {
287 return encodeVecTypeHint(getMDOperandAsType(Node, 1));
288 }
289
290 SPIRAddressSpace
getOCLOpaqueTypeAddrSpace(Op OpCode)291 getOCLOpaqueTypeAddrSpace(Op OpCode) {
292 switch (OpCode) {
293 case OpTypeQueue:
294 return SPIRV_QUEUE_T_ADDR_SPACE;
295 case OpTypeEvent:
296 return SPIRV_EVENT_T_ADDR_SPACE;
297 case OpTypeDeviceEvent:
298 return SPIRV_CLK_EVENT_T_ADDR_SPACE;
299 case OpTypeReserveId:
300 return SPIRV_RESERVE_ID_T_ADDR_SPACE;
301 case OpTypePipe:
302 case OpTypePipeStorage:
303 return SPIRV_PIPE_ADDR_SPACE;
304 case OpTypeImage:
305 case OpTypeSampledImage:
306 return SPIRV_IMAGE_ADDR_SPACE;
307 default:
308 assert(false && "No address space is determined for some OCL type");
309 return SPIRV_OCL_SPECIAL_TYPES_DEFAULT_ADDR_SPACE;
310 }
311 }
312
313 static SPIR::TypeAttributeEnum
mapAddrSpaceEnums(SPIRAddressSpace addrspace)314 mapAddrSpaceEnums(SPIRAddressSpace addrspace)
315 {
316 switch (addrspace) {
317 case SPIRAS_Private:
318 return SPIR::ATTR_PRIVATE;
319 case SPIRAS_Global:
320 return SPIR::ATTR_GLOBAL;
321 case SPIRAS_Constant:
322 return SPIR::ATTR_CONSTANT;
323 case SPIRAS_Local:
324 return SPIR::ATTR_LOCAL;
325 case SPIRAS_Generic:
326 return SPIR::ATTR_GENERIC;
327 default:
328 llvm_unreachable("Invalid addrspace enum member");
329 }
330 }
331
332 SPIR::TypeAttributeEnum
getOCLOpaqueTypeAddrSpace(SPIR::TypePrimitiveEnum prim)333 getOCLOpaqueTypeAddrSpace(SPIR::TypePrimitiveEnum prim) {
334 switch (prim) {
335 case SPIR::PRIMITIVE_QUEUE_T:
336 return mapAddrSpaceEnums(SPIRV_QUEUE_T_ADDR_SPACE);
337 case SPIR::PRIMITIVE_EVENT_T:
338 return mapAddrSpaceEnums(SPIRV_EVENT_T_ADDR_SPACE);
339 case SPIR::PRIMITIVE_CLK_EVENT_T:
340 return mapAddrSpaceEnums(SPIRV_CLK_EVENT_T_ADDR_SPACE);
341 case SPIR::PRIMITIVE_RESERVE_ID_T:
342 return mapAddrSpaceEnums(SPIRV_RESERVE_ID_T_ADDR_SPACE);
343 case SPIR::PRIMITIVE_PIPE_T:
344 return mapAddrSpaceEnums(SPIRV_PIPE_ADDR_SPACE);
345 case SPIR::PRIMITIVE_IMAGE_1D_T:
346 case SPIR::PRIMITIVE_IMAGE_1D_ARRAY_T:
347 case SPIR::PRIMITIVE_IMAGE_1D_BUFFER_T:
348 case SPIR::PRIMITIVE_IMAGE_2D_T:
349 case SPIR::PRIMITIVE_IMAGE_2D_ARRAY_T:
350 case SPIR::PRIMITIVE_IMAGE_3D_T:
351 case SPIR::PRIMITIVE_IMAGE_2D_MSAA_T:
352 case SPIR::PRIMITIVE_IMAGE_2D_ARRAY_MSAA_T:
353 case SPIR::PRIMITIVE_IMAGE_2D_MSAA_DEPTH_T:
354 case SPIR::PRIMITIVE_IMAGE_2D_ARRAY_MSAA_DEPTH_T:
355 case SPIR::PRIMITIVE_IMAGE_2D_DEPTH_T:
356 case SPIR::PRIMITIVE_IMAGE_2D_ARRAY_DEPTH_T:
357 return mapAddrSpaceEnums(SPIRV_IMAGE_ADDR_SPACE);
358 default:
359 llvm_unreachable("No address space is determined for a SPIR primitive");
360 }
361 }
362
363 // Fetch type of invoke function passed to device execution built-ins
364 static FunctionType *
getBlockInvokeTy(Function * F,unsigned blockIdx)365 getBlockInvokeTy(Function * F, unsigned blockIdx) {
366 auto params = F->getFunctionType()->params();
367 PointerType * funcPtr = cast<PointerType>(params[blockIdx]);
368 return cast<FunctionType>(funcPtr->getElementType());
369 }
370
371 class OCLBuiltinFuncMangleInfo : public SPIRV::BuiltinFuncMangleInfo {
372 public:
OCLBuiltinFuncMangleInfo(Function * f)373 OCLBuiltinFuncMangleInfo(Function * f) : F(f) {}
init(const std::string & UniqName)374 void init(const std::string &UniqName) {
375 UnmangledName = UniqName;
376 size_t Pos = std::string::npos;
377
378 if (UnmangledName.find("async_work_group") == 0) {
379 addUnsignedArg(-1);
380 setArgAttr(1, SPIR::ATTR_CONST);
381 } else if (UnmangledName.find("write_imageui") == 0)
382 addUnsignedArg(2);
383 else if (UnmangledName == "prefetch") {
384 addUnsignedArg(1);
385 setArgAttr(0, SPIR::ATTR_CONST);
386 } else if(UnmangledName == "get_kernel_work_group_size" ||
387 UnmangledName == "get_kernel_preferred_work_group_size_multiple") {
388 assert(F && "lack of necessary information");
389 const size_t blockArgIdx = 0;
390 FunctionType * InvokeTy = getBlockInvokeTy(F, blockArgIdx);
391 if(InvokeTy->getNumParams() > 1) setLocalArgBlock(blockArgIdx);
392 } else if (UnmangledName == "enqueue_kernel") {
393 assert(F && "lack of necessary information");
394 setEnumArg(1, SPIR::PRIMITIVE_KERNEL_ENQUEUE_FLAGS_T);
395 addUnsignedArg(3);
396 setArgAttr(4, SPIR::ATTR_CONST);
397 // If there are arguments other then block context then these are pointers
398 // to local memory so this built-in must be mangled accordingly.
399 const size_t blockArgIdx = 6;
400 FunctionType * InvokeTy = getBlockInvokeTy(F, blockArgIdx);
401 if(InvokeTy->getNumParams() > 1) {
402 setLocalArgBlock(blockArgIdx);
403 addUnsignedArg(blockArgIdx + 1);
404 setVarArg(blockArgIdx + 2);
405 }
406 } else if (UnmangledName.find("get_") == 0 ||
407 UnmangledName == "nan" ||
408 UnmangledName == "mem_fence" ||
409 UnmangledName.find("shuffle") == 0){
410 addUnsignedArg(-1);
411 if (UnmangledName.find(kOCLBuiltinName::GetFence) == 0){
412 setArgAttr(0, SPIR::ATTR_CONST);
413 addVoidPtrArg(0);
414 }
415 } else if (UnmangledName.find("barrier") == 0 ||
416 UnmangledName.find("work_group_barrier") == 0 ||
417 UnmangledName.find("sub_group_barrier") == 0) {
418 addUnsignedArg(0);
419 } else if (UnmangledName.find("atomic_work_item_fence") == 0) {
420 addUnsignedArg(0);
421 } else if (UnmangledName.find("atomic") == 0) {
422 setArgAttr(0, SPIR::ATTR_VOLATILE);
423 if (UnmangledName.find("atomic_umax") == 0 ||
424 UnmangledName.find("atomic_umin") == 0) {
425 addUnsignedArg(0);
426 addUnsignedArg(1);
427 UnmangledName.erase(7, 1);
428 } else if (UnmangledName.find("atomic_fetch_umin") == 0 ||
429 UnmangledName.find("atomic_fetch_umax") == 0) {
430 addUnsignedArg(0);
431 addUnsignedArg(1);
432 UnmangledName.erase(13, 1);
433 }
434 // Don't set atomic property to the first argument of 1.2 atomic built-ins.
435 if(UnmangledName.find("atomic_add") != 0 && UnmangledName.find("atomic_sub") != 0 &&
436 UnmangledName.find("atomic_xchg") != 0 && UnmangledName.find("atomic_inc") != 0 &&
437 UnmangledName.find("atomic_dec") != 0 && UnmangledName.find("atomic_cmpxchg") != 0 &&
438 UnmangledName.find("atomic_min") != 0 && UnmangledName.find("atomic_max") != 0 &&
439 UnmangledName.find("atomic_and") != 0 && UnmangledName.find("atomic_or") != 0 &&
440 UnmangledName.find("atomic_xor") != 0 && UnmangledName.find("atom_") != 0) {
441 addAtomicArg(0);
442 }
443
444 } else if (UnmangledName.find("uconvert_") == 0) {
445 addUnsignedArg(0);
446 UnmangledName.erase(0, 1);
447 } else if (UnmangledName.find("s_") == 0) {
448 UnmangledName.erase(0, 2);
449 } else if (UnmangledName.find("u_") == 0) {
450 addUnsignedArg(-1);
451 UnmangledName.erase(0, 2);
452 } else if (UnmangledName == "fclamp") {
453 UnmangledName.erase(0, 1);
454 } else if (UnmangledName == "read_pipe" || UnmangledName == "write_pipe") {
455 assert(F && "lack of necessary information");
456 // handle [read|write]pipe builtins (plus two i32 literal args
457 // required by SPIR 2.0 provisional specification):
458 if (F->getArgumentList().size() == 6) {
459 // with 4 arguments (plus two i32 literals):
460 // int read_pipe (read_only pipe gentype p, reserve_id_t reserve_id, uint index, gentype *ptr)
461 // int write_pipe (write_only pipe gentype p, reserve_id_t reserve_id, uint index, const gentype *ptr)
462 addUnsignedArg(2);
463 addVoidPtrArg(3);
464 addUnsignedArg(4);
465 addUnsignedArg(5);
466 } else if (F->getArgumentList().size() == 4) {
467 // with 2 arguments (plus two i32 literals):
468 // int read_pipe (read_only pipe gentype p, gentype *ptr)
469 // int write_pipe (write_only pipe gentype p, const gentype *ptr)
470 addVoidPtrArg(1);
471 addUnsignedArg(2);
472 addUnsignedArg(3);
473 } else {
474 llvm_unreachable("read/write pipe builtin with unexpected number of arguments");
475 }
476 } else if (UnmangledName.find("reserve_read_pipe") != std::string::npos ||
477 UnmangledName.find("reserve_write_pipe") != std::string::npos) {
478 // process [|work_group|sub_group]reserve[read|write]pipe builtins
479 addUnsignedArg(1);
480 addUnsignedArg(2);
481 addUnsignedArg(3);
482 } else if (UnmangledName.find("commit_read_pipe") != std::string::npos ||
483 UnmangledName.find("commit_write_pipe") != std::string::npos) {
484 // process [|work_group|sub_group]commit[read|write]pipe builtins
485 addUnsignedArg(2);
486 addUnsignedArg(3);
487 } else if (UnmangledName == "capture_event_profiling_info") {
488 addVoidPtrArg(2);
489 setEnumArg(1, SPIR::PRIMITIVE_CLK_PROFILING_INFO);
490 } else if (UnmangledName == "enqueue_marker") {
491 setArgAttr(2, SPIR::ATTR_CONST);
492 addUnsignedArg(1);
493 } else if (UnmangledName.find("vload") == 0) {
494 addUnsignedArg(0);
495 setArgAttr(1, SPIR::ATTR_CONST);
496 } else if (UnmangledName.find("vstore") == 0 ){
497 addUnsignedArg(1);
498 } else if (UnmangledName.find("ndrange_") == 0) {
499 addUnsignedArg(-1);
500 if (UnmangledName[8] == '2' || UnmangledName[8] == '3') {
501 setArgAttr(-1, SPIR::ATTR_CONST);
502 }
503 } else if ((Pos = UnmangledName.find("umax")) != std::string::npos ||
504 (Pos = UnmangledName.find("umin")) != std::string::npos) {
505 addUnsignedArg(-1);
506 UnmangledName.erase(Pos, 1);
507 } else if (UnmangledName.find("broadcast") != std::string::npos)
508 addUnsignedArg(-1);
509 else if (UnmangledName.find(kOCLBuiltinName::SampledReadImage) == 0) {
510 UnmangledName.erase(0, strlen(kOCLBuiltinName::Sampled));
511 addSamplerArg(1);
512 }
513 }
514 // Auxiliarry information, it is expected what it is relevant at the moment
515 // the init method is called.
516 Function * F; // SPIRV decorated function
517 };
518
519 CallInst *
mutateCallInstOCL(Module * M,CallInst * CI,std::function<std::string (CallInst *,std::vector<Value * > &)> ArgMutate,AttributeSet * Attrs)520 mutateCallInstOCL(Module *M, CallInst *CI,
521 std::function<std::string (CallInst *, std::vector<Value *> &)>ArgMutate,
522 AttributeSet *Attrs) {
523 OCLBuiltinFuncMangleInfo BtnInfo(CI->getCalledFunction());
524 return mutateCallInst(M, CI, ArgMutate, &BtnInfo, Attrs);
525 }
526
527 Instruction *
mutateCallInstOCL(Module * M,CallInst * CI,std::function<std::string (CallInst *,std::vector<Value * > &,Type * & RetTy)> ArgMutate,std::function<Instruction * (CallInst *)> RetMutate,AttributeSet * Attrs)528 mutateCallInstOCL(Module *M, CallInst *CI,
529 std::function<std::string (CallInst *, std::vector<Value *> &,
530 Type *&RetTy)> ArgMutate,
531 std::function<Instruction *(CallInst *)> RetMutate,
532 AttributeSet *Attrs) {
533 OCLBuiltinFuncMangleInfo BtnInfo(CI->getCalledFunction());
534 return mutateCallInst(M, CI, ArgMutate, RetMutate, &BtnInfo, Attrs);
535 }
536
537 void
mutateFunctionOCL(Function * F,std::function<std::string (CallInst *,std::vector<Value * > &)> ArgMutate,AttributeSet * Attrs)538 mutateFunctionOCL(Function *F,
539 std::function<std::string (CallInst *, std::vector<Value *> &)>ArgMutate,
540 AttributeSet *Attrs) {
541 OCLBuiltinFuncMangleInfo BtnInfo(F);
542 return mutateFunction(F, ArgMutate, &BtnInfo, Attrs, false);
543 }
544
545 static std::pair<StringRef, StringRef>
getSrcAndDstElememntTypeName(BitCastInst * BIC)546 getSrcAndDstElememntTypeName(BitCastInst* BIC) {
547 if (!BIC)
548 return std::pair<StringRef, StringRef>("", "");
549
550 Type *SrcTy = BIC->getSrcTy();
551 Type *DstTy = BIC->getDestTy();
552 if (SrcTy->isPointerTy())
553 SrcTy = SrcTy->getPointerElementType();
554 if (DstTy->isPointerTy())
555 DstTy = DstTy->getPointerElementType();
556 auto SrcST = dyn_cast<StructType>(SrcTy);
557 auto DstST = dyn_cast<StructType>(DstTy);
558 if (!DstST || !DstST->hasName() || !SrcST || !SrcST->hasName())
559 return std::pair<StringRef, StringRef>("", "");
560
561 return std::make_pair(SrcST->getName(), DstST->getName());
562 }
563
564 bool
isSamplerInitializer(Instruction * Inst)565 isSamplerInitializer(Instruction *Inst) {
566 BitCastInst *BIC = dyn_cast<BitCastInst>(Inst);
567 auto Names = getSrcAndDstElememntTypeName(BIC);
568 if (Names.second == getSPIRVTypeName(kSPIRVTypeName::Sampler) &&
569 Names.first == getSPIRVTypeName(kSPIRVTypeName::ConstantSampler))
570 return true;
571
572 return false;
573 }
574
575 bool
isPipeStorageInitializer(Instruction * Inst)576 isPipeStorageInitializer(Instruction *Inst) {
577 BitCastInst *BIC = dyn_cast<BitCastInst>(Inst);
578 auto Names = getSrcAndDstElememntTypeName(BIC);
579 if (Names.second == getSPIRVTypeName(kSPIRVTypeName::PipeStorage) &&
580 Names.first == getSPIRVTypeName(kSPIRVTypeName::ConstantPipeStorage))
581 return true;
582
583 return false;
584 }
585
586 bool
isSpecialTypeInitializer(Instruction * Inst)587 isSpecialTypeInitializer(Instruction* Inst) {
588 return isSamplerInitializer(Inst) || isPipeStorageInitializer(Inst);
589 }
590
591 } // namespace OCLUtil
592
593 void
MangleOpenCLBuiltin(const std::string & UniqName,ArrayRef<Type * > ArgTypes,std::string & MangledName)594 llvm::MangleOpenCLBuiltin(const std::string &UniqName,
595 ArrayRef<Type*> ArgTypes, std::string &MangledName) {
596 OCLUtil::OCLBuiltinFuncMangleInfo BtnInfo(nullptr);
597 MangledName = SPIRV::mangleBuiltin(UniqName, ArgTypes, &BtnInfo);
598 }
599