• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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