181ad6265SDimitry Andric //===--- SPIRVUtils.cpp ---- SPIR-V Utility Functions -----------*- C++ -*-===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric // 981ad6265SDimitry Andric // This file contains miscellaneous utility functions. 1081ad6265SDimitry Andric // 1181ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1281ad6265SDimitry Andric 1381ad6265SDimitry Andric #include "SPIRVUtils.h" 1481ad6265SDimitry Andric #include "MCTargetDesc/SPIRVBaseInfo.h" 1581ad6265SDimitry Andric #include "SPIRV.h" 1681ad6265SDimitry Andric #include "SPIRVInstrInfo.h" 1781ad6265SDimitry Andric #include "llvm/ADT/StringRef.h" 1881ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 1981ad6265SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 2081ad6265SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 21*bdd1243dSDimitry Andric #include "llvm/Demangle/Demangle.h" 2281ad6265SDimitry Andric #include "llvm/IR/IntrinsicsSPIRV.h" 2381ad6265SDimitry Andric 24*bdd1243dSDimitry Andric namespace llvm { 2581ad6265SDimitry Andric 2681ad6265SDimitry Andric // The following functions are used to add these string literals as a series of 2781ad6265SDimitry Andric // 32-bit integer operands with the correct format, and unpack them if necessary 2881ad6265SDimitry Andric // when making string comparisons in compiler passes. 2981ad6265SDimitry Andric // SPIR-V requires null-terminated UTF-8 strings padded to 32-bit alignment. 3081ad6265SDimitry Andric static uint32_t convertCharsToWord(const StringRef &Str, unsigned i) { 3181ad6265SDimitry Andric uint32_t Word = 0u; // Build up this 32-bit word from 4 8-bit chars. 3281ad6265SDimitry Andric for (unsigned WordIndex = 0; WordIndex < 4; ++WordIndex) { 3381ad6265SDimitry Andric unsigned StrIndex = i + WordIndex; 3481ad6265SDimitry Andric uint8_t CharToAdd = 0; // Initilize char as padding/null. 3581ad6265SDimitry Andric if (StrIndex < Str.size()) { // If it's within the string, get a real char. 3681ad6265SDimitry Andric CharToAdd = Str[StrIndex]; 3781ad6265SDimitry Andric } 3881ad6265SDimitry Andric Word |= (CharToAdd << (WordIndex * 8)); 3981ad6265SDimitry Andric } 4081ad6265SDimitry Andric return Word; 4181ad6265SDimitry Andric } 4281ad6265SDimitry Andric 4381ad6265SDimitry Andric // Get length including padding and null terminator. 4481ad6265SDimitry Andric static size_t getPaddedLen(const StringRef &Str) { 4581ad6265SDimitry Andric const size_t Len = Str.size() + 1; 4681ad6265SDimitry Andric return (Len % 4 == 0) ? Len : Len + (4 - (Len % 4)); 4781ad6265SDimitry Andric } 4881ad6265SDimitry Andric 49fcaf7f86SDimitry Andric void addStringImm(const StringRef &Str, MCInst &Inst) { 50fcaf7f86SDimitry Andric const size_t PaddedLen = getPaddedLen(Str); 51fcaf7f86SDimitry Andric for (unsigned i = 0; i < PaddedLen; i += 4) { 52fcaf7f86SDimitry Andric // Add an operand for the 32-bits of chars or padding. 53fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createImm(convertCharsToWord(Str, i))); 54fcaf7f86SDimitry Andric } 55fcaf7f86SDimitry Andric } 56fcaf7f86SDimitry Andric 5781ad6265SDimitry Andric void addStringImm(const StringRef &Str, MachineInstrBuilder &MIB) { 5881ad6265SDimitry Andric const size_t PaddedLen = getPaddedLen(Str); 5981ad6265SDimitry Andric for (unsigned i = 0; i < PaddedLen; i += 4) { 6081ad6265SDimitry Andric // Add an operand for the 32-bits of chars or padding. 6181ad6265SDimitry Andric MIB.addImm(convertCharsToWord(Str, i)); 6281ad6265SDimitry Andric } 6381ad6265SDimitry Andric } 6481ad6265SDimitry Andric 6581ad6265SDimitry Andric void addStringImm(const StringRef &Str, IRBuilder<> &B, 6681ad6265SDimitry Andric std::vector<Value *> &Args) { 6781ad6265SDimitry Andric const size_t PaddedLen = getPaddedLen(Str); 6881ad6265SDimitry Andric for (unsigned i = 0; i < PaddedLen; i += 4) { 6981ad6265SDimitry Andric // Add a vector element for the 32-bits of chars or padding. 7081ad6265SDimitry Andric Args.push_back(B.getInt32(convertCharsToWord(Str, i))); 7181ad6265SDimitry Andric } 7281ad6265SDimitry Andric } 7381ad6265SDimitry Andric 7481ad6265SDimitry Andric std::string getStringImm(const MachineInstr &MI, unsigned StartIndex) { 7581ad6265SDimitry Andric return getSPIRVStringOperand(MI, StartIndex); 7681ad6265SDimitry Andric } 7781ad6265SDimitry Andric 7881ad6265SDimitry Andric void addNumImm(const APInt &Imm, MachineInstrBuilder &MIB) { 7981ad6265SDimitry Andric const auto Bitwidth = Imm.getBitWidth(); 8081ad6265SDimitry Andric switch (Bitwidth) { 8181ad6265SDimitry Andric case 1: 8281ad6265SDimitry Andric break; // Already handled. 8381ad6265SDimitry Andric case 8: 8481ad6265SDimitry Andric case 16: 8581ad6265SDimitry Andric case 32: 8681ad6265SDimitry Andric MIB.addImm(Imm.getZExtValue()); 8781ad6265SDimitry Andric break; 8881ad6265SDimitry Andric case 64: { 8981ad6265SDimitry Andric uint64_t FullImm = Imm.getZExtValue(); 9081ad6265SDimitry Andric uint32_t LowBits = FullImm & 0xffffffff; 9181ad6265SDimitry Andric uint32_t HighBits = (FullImm >> 32) & 0xffffffff; 9281ad6265SDimitry Andric MIB.addImm(LowBits).addImm(HighBits); 9381ad6265SDimitry Andric break; 9481ad6265SDimitry Andric } 9581ad6265SDimitry Andric default: 9681ad6265SDimitry Andric report_fatal_error("Unsupported constant bitwidth"); 9781ad6265SDimitry Andric } 9881ad6265SDimitry Andric } 9981ad6265SDimitry Andric 10081ad6265SDimitry Andric void buildOpName(Register Target, const StringRef &Name, 10181ad6265SDimitry Andric MachineIRBuilder &MIRBuilder) { 10281ad6265SDimitry Andric if (!Name.empty()) { 10381ad6265SDimitry Andric auto MIB = MIRBuilder.buildInstr(SPIRV::OpName).addUse(Target); 10481ad6265SDimitry Andric addStringImm(Name, MIB); 10581ad6265SDimitry Andric } 10681ad6265SDimitry Andric } 10781ad6265SDimitry Andric 10881ad6265SDimitry Andric static void finishBuildOpDecorate(MachineInstrBuilder &MIB, 10981ad6265SDimitry Andric const std::vector<uint32_t> &DecArgs, 11081ad6265SDimitry Andric StringRef StrImm) { 11181ad6265SDimitry Andric if (!StrImm.empty()) 11281ad6265SDimitry Andric addStringImm(StrImm, MIB); 11381ad6265SDimitry Andric for (const auto &DecArg : DecArgs) 11481ad6265SDimitry Andric MIB.addImm(DecArg); 11581ad6265SDimitry Andric } 11681ad6265SDimitry Andric 11781ad6265SDimitry Andric void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, 118*bdd1243dSDimitry Andric SPIRV::Decoration::Decoration Dec, 11981ad6265SDimitry Andric const std::vector<uint32_t> &DecArgs, StringRef StrImm) { 12081ad6265SDimitry Andric auto MIB = MIRBuilder.buildInstr(SPIRV::OpDecorate) 12181ad6265SDimitry Andric .addUse(Reg) 12281ad6265SDimitry Andric .addImm(static_cast<uint32_t>(Dec)); 12381ad6265SDimitry Andric finishBuildOpDecorate(MIB, DecArgs, StrImm); 12481ad6265SDimitry Andric } 12581ad6265SDimitry Andric 12681ad6265SDimitry Andric void buildOpDecorate(Register Reg, MachineInstr &I, const SPIRVInstrInfo &TII, 127*bdd1243dSDimitry Andric SPIRV::Decoration::Decoration Dec, 12881ad6265SDimitry Andric const std::vector<uint32_t> &DecArgs, StringRef StrImm) { 12981ad6265SDimitry Andric MachineBasicBlock &MBB = *I.getParent(); 13081ad6265SDimitry Andric auto MIB = BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpDecorate)) 13181ad6265SDimitry Andric .addUse(Reg) 13281ad6265SDimitry Andric .addImm(static_cast<uint32_t>(Dec)); 13381ad6265SDimitry Andric finishBuildOpDecorate(MIB, DecArgs, StrImm); 13481ad6265SDimitry Andric } 13581ad6265SDimitry Andric 13681ad6265SDimitry Andric // TODO: maybe the following two functions should be handled in the subtarget 13781ad6265SDimitry Andric // to allow for different OpenCL vs Vulkan handling. 138*bdd1243dSDimitry Andric unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC) { 13981ad6265SDimitry Andric switch (SC) { 14081ad6265SDimitry Andric case SPIRV::StorageClass::Function: 14181ad6265SDimitry Andric return 0; 14281ad6265SDimitry Andric case SPIRV::StorageClass::CrossWorkgroup: 14381ad6265SDimitry Andric return 1; 14481ad6265SDimitry Andric case SPIRV::StorageClass::UniformConstant: 14581ad6265SDimitry Andric return 2; 14681ad6265SDimitry Andric case SPIRV::StorageClass::Workgroup: 14781ad6265SDimitry Andric return 3; 14881ad6265SDimitry Andric case SPIRV::StorageClass::Generic: 14981ad6265SDimitry Andric return 4; 15081ad6265SDimitry Andric case SPIRV::StorageClass::Input: 15181ad6265SDimitry Andric return 7; 15281ad6265SDimitry Andric default: 15381ad6265SDimitry Andric llvm_unreachable("Unable to get address space id"); 15481ad6265SDimitry Andric } 15581ad6265SDimitry Andric } 15681ad6265SDimitry Andric 157*bdd1243dSDimitry Andric SPIRV::StorageClass::StorageClass 158*bdd1243dSDimitry Andric addressSpaceToStorageClass(unsigned AddrSpace) { 15981ad6265SDimitry Andric switch (AddrSpace) { 16081ad6265SDimitry Andric case 0: 16181ad6265SDimitry Andric return SPIRV::StorageClass::Function; 16281ad6265SDimitry Andric case 1: 16381ad6265SDimitry Andric return SPIRV::StorageClass::CrossWorkgroup; 16481ad6265SDimitry Andric case 2: 16581ad6265SDimitry Andric return SPIRV::StorageClass::UniformConstant; 16681ad6265SDimitry Andric case 3: 16781ad6265SDimitry Andric return SPIRV::StorageClass::Workgroup; 16881ad6265SDimitry Andric case 4: 16981ad6265SDimitry Andric return SPIRV::StorageClass::Generic; 17081ad6265SDimitry Andric case 7: 17181ad6265SDimitry Andric return SPIRV::StorageClass::Input; 17281ad6265SDimitry Andric default: 17381ad6265SDimitry Andric llvm_unreachable("Unknown address space"); 17481ad6265SDimitry Andric } 17581ad6265SDimitry Andric } 17681ad6265SDimitry Andric 177*bdd1243dSDimitry Andric SPIRV::MemorySemantics::MemorySemantics 178*bdd1243dSDimitry Andric getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC) { 17981ad6265SDimitry Andric switch (SC) { 18081ad6265SDimitry Andric case SPIRV::StorageClass::StorageBuffer: 18181ad6265SDimitry Andric case SPIRV::StorageClass::Uniform: 18281ad6265SDimitry Andric return SPIRV::MemorySemantics::UniformMemory; 18381ad6265SDimitry Andric case SPIRV::StorageClass::Workgroup: 18481ad6265SDimitry Andric return SPIRV::MemorySemantics::WorkgroupMemory; 18581ad6265SDimitry Andric case SPIRV::StorageClass::CrossWorkgroup: 18681ad6265SDimitry Andric return SPIRV::MemorySemantics::CrossWorkgroupMemory; 18781ad6265SDimitry Andric case SPIRV::StorageClass::AtomicCounter: 18881ad6265SDimitry Andric return SPIRV::MemorySemantics::AtomicCounterMemory; 18981ad6265SDimitry Andric case SPIRV::StorageClass::Image: 19081ad6265SDimitry Andric return SPIRV::MemorySemantics::ImageMemory; 19181ad6265SDimitry Andric default: 19281ad6265SDimitry Andric return SPIRV::MemorySemantics::None; 19381ad6265SDimitry Andric } 19481ad6265SDimitry Andric } 19581ad6265SDimitry Andric 196*bdd1243dSDimitry Andric SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord) { 197fcaf7f86SDimitry Andric switch (Ord) { 198fcaf7f86SDimitry Andric case AtomicOrdering::Acquire: 199fcaf7f86SDimitry Andric return SPIRV::MemorySemantics::Acquire; 200fcaf7f86SDimitry Andric case AtomicOrdering::Release: 201fcaf7f86SDimitry Andric return SPIRV::MemorySemantics::Release; 202fcaf7f86SDimitry Andric case AtomicOrdering::AcquireRelease: 203fcaf7f86SDimitry Andric return SPIRV::MemorySemantics::AcquireRelease; 204fcaf7f86SDimitry Andric case AtomicOrdering::SequentiallyConsistent: 205fcaf7f86SDimitry Andric return SPIRV::MemorySemantics::SequentiallyConsistent; 206fcaf7f86SDimitry Andric case AtomicOrdering::Unordered: 207fcaf7f86SDimitry Andric case AtomicOrdering::Monotonic: 208fcaf7f86SDimitry Andric case AtomicOrdering::NotAtomic: 209fcaf7f86SDimitry Andric default: 210fcaf7f86SDimitry Andric return SPIRV::MemorySemantics::None; 211fcaf7f86SDimitry Andric } 212fcaf7f86SDimitry Andric } 213fcaf7f86SDimitry Andric 21481ad6265SDimitry Andric MachineInstr *getDefInstrMaybeConstant(Register &ConstReg, 21581ad6265SDimitry Andric const MachineRegisterInfo *MRI) { 21681ad6265SDimitry Andric MachineInstr *ConstInstr = MRI->getVRegDef(ConstReg); 21781ad6265SDimitry Andric if (ConstInstr->getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS && 21881ad6265SDimitry Andric ConstInstr->getIntrinsicID() == Intrinsic::spv_track_constant) { 21981ad6265SDimitry Andric ConstReg = ConstInstr->getOperand(2).getReg(); 22081ad6265SDimitry Andric ConstInstr = MRI->getVRegDef(ConstReg); 22181ad6265SDimitry Andric } else if (ConstInstr->getOpcode() == SPIRV::ASSIGN_TYPE) { 22281ad6265SDimitry Andric ConstReg = ConstInstr->getOperand(1).getReg(); 22381ad6265SDimitry Andric ConstInstr = MRI->getVRegDef(ConstReg); 22481ad6265SDimitry Andric } 22581ad6265SDimitry Andric return ConstInstr; 22681ad6265SDimitry Andric } 22781ad6265SDimitry Andric 22881ad6265SDimitry Andric uint64_t getIConstVal(Register ConstReg, const MachineRegisterInfo *MRI) { 22981ad6265SDimitry Andric const MachineInstr *MI = getDefInstrMaybeConstant(ConstReg, MRI); 23081ad6265SDimitry Andric assert(MI && MI->getOpcode() == TargetOpcode::G_CONSTANT); 23181ad6265SDimitry Andric return MI->getOperand(1).getCImm()->getValue().getZExtValue(); 23281ad6265SDimitry Andric } 23381ad6265SDimitry Andric 234fcaf7f86SDimitry Andric bool isSpvIntrinsic(MachineInstr &MI, Intrinsic::ID IntrinsicID) { 235fcaf7f86SDimitry Andric return MI.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS && 236fcaf7f86SDimitry Andric MI.getIntrinsicID() == IntrinsicID; 237fcaf7f86SDimitry Andric } 238fcaf7f86SDimitry Andric 23981ad6265SDimitry Andric Type *getMDOperandAsType(const MDNode *N, unsigned I) { 24081ad6265SDimitry Andric return cast<ValueAsMetadata>(N->getOperand(I))->getType(); 24181ad6265SDimitry Andric } 242*bdd1243dSDimitry Andric 243*bdd1243dSDimitry Andric // The set of names is borrowed from the SPIR-V translator. 244*bdd1243dSDimitry Andric // TODO: may be implemented in SPIRVBuiltins.td. 245*bdd1243dSDimitry Andric static bool isPipeOrAddressSpaceCastBI(const StringRef MangledName) { 246*bdd1243dSDimitry Andric return MangledName == "write_pipe_2" || MangledName == "read_pipe_2" || 247*bdd1243dSDimitry Andric MangledName == "write_pipe_2_bl" || MangledName == "read_pipe_2_bl" || 248*bdd1243dSDimitry Andric MangledName == "write_pipe_4" || MangledName == "read_pipe_4" || 249*bdd1243dSDimitry Andric MangledName == "reserve_write_pipe" || 250*bdd1243dSDimitry Andric MangledName == "reserve_read_pipe" || 251*bdd1243dSDimitry Andric MangledName == "commit_write_pipe" || 252*bdd1243dSDimitry Andric MangledName == "commit_read_pipe" || 253*bdd1243dSDimitry Andric MangledName == "work_group_reserve_write_pipe" || 254*bdd1243dSDimitry Andric MangledName == "work_group_reserve_read_pipe" || 255*bdd1243dSDimitry Andric MangledName == "work_group_commit_write_pipe" || 256*bdd1243dSDimitry Andric MangledName == "work_group_commit_read_pipe" || 257*bdd1243dSDimitry Andric MangledName == "get_pipe_num_packets_ro" || 258*bdd1243dSDimitry Andric MangledName == "get_pipe_max_packets_ro" || 259*bdd1243dSDimitry Andric MangledName == "get_pipe_num_packets_wo" || 260*bdd1243dSDimitry Andric MangledName == "get_pipe_max_packets_wo" || 261*bdd1243dSDimitry Andric MangledName == "sub_group_reserve_write_pipe" || 262*bdd1243dSDimitry Andric MangledName == "sub_group_reserve_read_pipe" || 263*bdd1243dSDimitry Andric MangledName == "sub_group_commit_write_pipe" || 264*bdd1243dSDimitry Andric MangledName == "sub_group_commit_read_pipe" || 265*bdd1243dSDimitry Andric MangledName == "to_global" || MangledName == "to_local" || 266*bdd1243dSDimitry Andric MangledName == "to_private"; 267*bdd1243dSDimitry Andric } 268*bdd1243dSDimitry Andric 269*bdd1243dSDimitry Andric static bool isEnqueueKernelBI(const StringRef MangledName) { 270*bdd1243dSDimitry Andric return MangledName == "__enqueue_kernel_basic" || 271*bdd1243dSDimitry Andric MangledName == "__enqueue_kernel_basic_events" || 272*bdd1243dSDimitry Andric MangledName == "__enqueue_kernel_varargs" || 273*bdd1243dSDimitry Andric MangledName == "__enqueue_kernel_events_varargs"; 274*bdd1243dSDimitry Andric } 275*bdd1243dSDimitry Andric 276*bdd1243dSDimitry Andric static bool isKernelQueryBI(const StringRef MangledName) { 277*bdd1243dSDimitry Andric return MangledName == "__get_kernel_work_group_size_impl" || 278*bdd1243dSDimitry Andric MangledName == "__get_kernel_sub_group_count_for_ndrange_impl" || 279*bdd1243dSDimitry Andric MangledName == "__get_kernel_max_sub_group_size_for_ndrange_impl" || 280*bdd1243dSDimitry Andric MangledName == "__get_kernel_preferred_work_group_size_multiple_impl"; 281*bdd1243dSDimitry Andric } 282*bdd1243dSDimitry Andric 283*bdd1243dSDimitry Andric static bool isNonMangledOCLBuiltin(StringRef Name) { 284*bdd1243dSDimitry Andric if (!Name.startswith("__")) 285*bdd1243dSDimitry Andric return false; 286*bdd1243dSDimitry Andric 287*bdd1243dSDimitry Andric return isEnqueueKernelBI(Name) || isKernelQueryBI(Name) || 288*bdd1243dSDimitry Andric isPipeOrAddressSpaceCastBI(Name.drop_front(2)) || 289*bdd1243dSDimitry Andric Name == "__translate_sampler_initializer"; 290*bdd1243dSDimitry Andric } 291*bdd1243dSDimitry Andric 292*bdd1243dSDimitry Andric std::string getOclOrSpirvBuiltinDemangledName(StringRef Name) { 293*bdd1243dSDimitry Andric bool IsNonMangledOCL = isNonMangledOCLBuiltin(Name); 294*bdd1243dSDimitry Andric bool IsNonMangledSPIRV = Name.startswith("__spirv_"); 295*bdd1243dSDimitry Andric bool IsMangled = Name.startswith("_Z"); 296*bdd1243dSDimitry Andric 297*bdd1243dSDimitry Andric if (!IsNonMangledOCL && !IsNonMangledSPIRV && !IsMangled) 298*bdd1243dSDimitry Andric return std::string(); 299*bdd1243dSDimitry Andric 300*bdd1243dSDimitry Andric // Try to use the itanium demangler. 301*bdd1243dSDimitry Andric size_t n; 302*bdd1243dSDimitry Andric int Status; 303*bdd1243dSDimitry Andric char *DemangledName = itaniumDemangle(Name.data(), nullptr, &n, &Status); 304*bdd1243dSDimitry Andric 305*bdd1243dSDimitry Andric if (Status == demangle_success) { 306*bdd1243dSDimitry Andric std::string Result = DemangledName; 307*bdd1243dSDimitry Andric free(DemangledName); 308*bdd1243dSDimitry Andric return Result; 309*bdd1243dSDimitry Andric } 310*bdd1243dSDimitry Andric free(DemangledName); 311*bdd1243dSDimitry Andric // Otherwise use simple demangling to return the function name. 312*bdd1243dSDimitry Andric if (IsNonMangledOCL || IsNonMangledSPIRV) 313*bdd1243dSDimitry Andric return Name.str(); 314*bdd1243dSDimitry Andric 315*bdd1243dSDimitry Andric // Autocheck C++, maybe need to do explicit check of the source language. 316*bdd1243dSDimitry Andric // OpenCL C++ built-ins are declared in cl namespace. 317*bdd1243dSDimitry Andric // TODO: consider using 'St' abbriviation for cl namespace mangling. 318*bdd1243dSDimitry Andric // Similar to ::std:: in C++. 319*bdd1243dSDimitry Andric size_t Start, Len = 0; 320*bdd1243dSDimitry Andric size_t DemangledNameLenStart = 2; 321*bdd1243dSDimitry Andric if (Name.startswith("_ZN")) { 322*bdd1243dSDimitry Andric // Skip CV and ref qualifiers. 323*bdd1243dSDimitry Andric size_t NameSpaceStart = Name.find_first_not_of("rVKRO", 3); 324*bdd1243dSDimitry Andric // All built-ins are in the ::cl:: namespace. 325*bdd1243dSDimitry Andric if (Name.substr(NameSpaceStart, 11) != "2cl7__spirv") 326*bdd1243dSDimitry Andric return std::string(); 327*bdd1243dSDimitry Andric DemangledNameLenStart = NameSpaceStart + 11; 328*bdd1243dSDimitry Andric } 329*bdd1243dSDimitry Andric Start = Name.find_first_not_of("0123456789", DemangledNameLenStart); 330*bdd1243dSDimitry Andric Name.substr(DemangledNameLenStart, Start - DemangledNameLenStart) 331*bdd1243dSDimitry Andric .getAsInteger(10, Len); 332*bdd1243dSDimitry Andric return Name.substr(Start, Len).str(); 333*bdd1243dSDimitry Andric } 334*bdd1243dSDimitry Andric 335*bdd1243dSDimitry Andric static bool isOpenCLBuiltinType(const StructType *SType) { 336*bdd1243dSDimitry Andric return SType->isOpaque() && SType->hasName() && 337*bdd1243dSDimitry Andric SType->getName().startswith("opencl."); 338*bdd1243dSDimitry Andric } 339*bdd1243dSDimitry Andric 340*bdd1243dSDimitry Andric static bool isSPIRVBuiltinType(const StructType *SType) { 341*bdd1243dSDimitry Andric return SType->isOpaque() && SType->hasName() && 342*bdd1243dSDimitry Andric SType->getName().startswith("spirv."); 343*bdd1243dSDimitry Andric } 344*bdd1243dSDimitry Andric 345*bdd1243dSDimitry Andric const Type *getTypedPtrEltType(const Type *Ty) { 346*bdd1243dSDimitry Andric auto PType = dyn_cast<PointerType>(Ty); 347*bdd1243dSDimitry Andric if (!PType || PType->isOpaque()) 348*bdd1243dSDimitry Andric return Ty; 349*bdd1243dSDimitry Andric return PType->getNonOpaquePointerElementType(); 350*bdd1243dSDimitry Andric } 351*bdd1243dSDimitry Andric 352*bdd1243dSDimitry Andric bool isSpecialOpaqueType(const Type *Ty) { 353*bdd1243dSDimitry Andric if (auto SType = dyn_cast<StructType>(getTypedPtrEltType(Ty))) 354*bdd1243dSDimitry Andric return isOpenCLBuiltinType(SType) || isSPIRVBuiltinType(SType); 355*bdd1243dSDimitry Andric return false; 356*bdd1243dSDimitry Andric } 357*bdd1243dSDimitry Andric } // namespace llvm 358