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 /////////////////////////////////////////////////////////////////////////////// 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 105 size_t getAtomicBuiltinNumMemoryOrderArgs(StringRef Name) { 106 if (Name.startswith("atomic_compare_exchange")) 107 return 2; 108 return 1; 109 } 110 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 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> 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 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> 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 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 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 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 * 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 286 transVecTypeHint(MDNode* Node) { 287 return encodeVecTypeHint(getMDOperandAsType(Node, 1)); 288 } 289 290 SPIRAddressSpace 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 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 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 * 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: 373 OCLBuiltinFuncMangleInfo(Function * f) : F(f) {} 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 * 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 * 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 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> 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 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 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 587 isSpecialTypeInitializer(Instruction* Inst) { 588 return isSamplerInitializer(Inst) || isPipeStorageInitializer(Inst); 589 } 590 591 } // namespace OCLUtil 592 593 void 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