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" 185f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h" 1981ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 2081ad6265SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 2181ad6265SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 22bdd1243dSDimitry Andric #include "llvm/Demangle/Demangle.h" 2381ad6265SDimitry Andric #include "llvm/IR/IntrinsicsSPIRV.h" 2481ad6265SDimitry Andric 25bdd1243dSDimitry Andric namespace llvm { 2681ad6265SDimitry Andric 2781ad6265SDimitry Andric // The following functions are used to add these string literals as a series of 2881ad6265SDimitry Andric // 32-bit integer operands with the correct format, and unpack them if necessary 2981ad6265SDimitry Andric // when making string comparisons in compiler passes. 3081ad6265SDimitry Andric // SPIR-V requires null-terminated UTF-8 strings padded to 32-bit alignment. 3181ad6265SDimitry Andric static uint32_t convertCharsToWord(const StringRef &Str, unsigned i) { 3281ad6265SDimitry Andric uint32_t Word = 0u; // Build up this 32-bit word from 4 8-bit chars. 3381ad6265SDimitry Andric for (unsigned WordIndex = 0; WordIndex < 4; ++WordIndex) { 3481ad6265SDimitry Andric unsigned StrIndex = i + WordIndex; 3581ad6265SDimitry Andric uint8_t CharToAdd = 0; // Initilize char as padding/null. 3681ad6265SDimitry Andric if (StrIndex < Str.size()) { // If it's within the string, get a real char. 3781ad6265SDimitry Andric CharToAdd = Str[StrIndex]; 3881ad6265SDimitry Andric } 3981ad6265SDimitry Andric Word |= (CharToAdd << (WordIndex * 8)); 4081ad6265SDimitry Andric } 4181ad6265SDimitry Andric return Word; 4281ad6265SDimitry Andric } 4381ad6265SDimitry Andric 4481ad6265SDimitry Andric // Get length including padding and null terminator. 4581ad6265SDimitry Andric static size_t getPaddedLen(const StringRef &Str) { 4681ad6265SDimitry Andric const size_t Len = Str.size() + 1; 4781ad6265SDimitry Andric return (Len % 4 == 0) ? Len : Len + (4 - (Len % 4)); 4881ad6265SDimitry Andric } 4981ad6265SDimitry Andric 50fcaf7f86SDimitry Andric void addStringImm(const StringRef &Str, MCInst &Inst) { 51fcaf7f86SDimitry Andric const size_t PaddedLen = getPaddedLen(Str); 52fcaf7f86SDimitry Andric for (unsigned i = 0; i < PaddedLen; i += 4) { 53fcaf7f86SDimitry Andric // Add an operand for the 32-bits of chars or padding. 54fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createImm(convertCharsToWord(Str, i))); 55fcaf7f86SDimitry Andric } 56fcaf7f86SDimitry Andric } 57fcaf7f86SDimitry Andric 5881ad6265SDimitry Andric void addStringImm(const StringRef &Str, MachineInstrBuilder &MIB) { 5981ad6265SDimitry Andric const size_t PaddedLen = getPaddedLen(Str); 6081ad6265SDimitry Andric for (unsigned i = 0; i < PaddedLen; i += 4) { 6181ad6265SDimitry Andric // Add an operand for the 32-bits of chars or padding. 6281ad6265SDimitry Andric MIB.addImm(convertCharsToWord(Str, i)); 6381ad6265SDimitry Andric } 6481ad6265SDimitry Andric } 6581ad6265SDimitry Andric 6681ad6265SDimitry Andric void addStringImm(const StringRef &Str, IRBuilder<> &B, 6781ad6265SDimitry Andric std::vector<Value *> &Args) { 6881ad6265SDimitry Andric const size_t PaddedLen = getPaddedLen(Str); 6981ad6265SDimitry Andric for (unsigned i = 0; i < PaddedLen; i += 4) { 7081ad6265SDimitry Andric // Add a vector element for the 32-bits of chars or padding. 7181ad6265SDimitry Andric Args.push_back(B.getInt32(convertCharsToWord(Str, i))); 7281ad6265SDimitry Andric } 7381ad6265SDimitry Andric } 7481ad6265SDimitry Andric 7581ad6265SDimitry Andric std::string getStringImm(const MachineInstr &MI, unsigned StartIndex) { 7681ad6265SDimitry Andric return getSPIRVStringOperand(MI, StartIndex); 7781ad6265SDimitry Andric } 7881ad6265SDimitry Andric 7981ad6265SDimitry Andric void addNumImm(const APInt &Imm, MachineInstrBuilder &MIB) { 8081ad6265SDimitry Andric const auto Bitwidth = Imm.getBitWidth(); 8106c3fb27SDimitry Andric if (Bitwidth == 1) 8206c3fb27SDimitry Andric return; // Already handled 8306c3fb27SDimitry Andric else if (Bitwidth <= 32) { 8481ad6265SDimitry Andric MIB.addImm(Imm.getZExtValue()); 8506c3fb27SDimitry Andric return; 8606c3fb27SDimitry Andric } else if (Bitwidth <= 64) { 8781ad6265SDimitry Andric uint64_t FullImm = Imm.getZExtValue(); 8881ad6265SDimitry Andric uint32_t LowBits = FullImm & 0xffffffff; 8981ad6265SDimitry Andric uint32_t HighBits = (FullImm >> 32) & 0xffffffff; 9081ad6265SDimitry Andric MIB.addImm(LowBits).addImm(HighBits); 9106c3fb27SDimitry Andric return; 9281ad6265SDimitry Andric } 9381ad6265SDimitry Andric report_fatal_error("Unsupported constant bitwidth"); 9481ad6265SDimitry Andric } 9581ad6265SDimitry Andric 9681ad6265SDimitry Andric void buildOpName(Register Target, const StringRef &Name, 9781ad6265SDimitry Andric MachineIRBuilder &MIRBuilder) { 9881ad6265SDimitry Andric if (!Name.empty()) { 9981ad6265SDimitry Andric auto MIB = MIRBuilder.buildInstr(SPIRV::OpName).addUse(Target); 10081ad6265SDimitry Andric addStringImm(Name, MIB); 10181ad6265SDimitry Andric } 10281ad6265SDimitry Andric } 10381ad6265SDimitry Andric 10481ad6265SDimitry Andric static void finishBuildOpDecorate(MachineInstrBuilder &MIB, 10581ad6265SDimitry Andric const std::vector<uint32_t> &DecArgs, 10681ad6265SDimitry Andric StringRef StrImm) { 10781ad6265SDimitry Andric if (!StrImm.empty()) 10881ad6265SDimitry Andric addStringImm(StrImm, MIB); 10981ad6265SDimitry Andric for (const auto &DecArg : DecArgs) 11081ad6265SDimitry Andric MIB.addImm(DecArg); 11181ad6265SDimitry Andric } 11281ad6265SDimitry Andric 11381ad6265SDimitry Andric void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, 114bdd1243dSDimitry Andric SPIRV::Decoration::Decoration Dec, 11581ad6265SDimitry Andric const std::vector<uint32_t> &DecArgs, StringRef StrImm) { 11681ad6265SDimitry Andric auto MIB = MIRBuilder.buildInstr(SPIRV::OpDecorate) 11781ad6265SDimitry Andric .addUse(Reg) 11881ad6265SDimitry Andric .addImm(static_cast<uint32_t>(Dec)); 11981ad6265SDimitry Andric finishBuildOpDecorate(MIB, DecArgs, StrImm); 12081ad6265SDimitry Andric } 12181ad6265SDimitry Andric 12281ad6265SDimitry Andric void buildOpDecorate(Register Reg, MachineInstr &I, const SPIRVInstrInfo &TII, 123bdd1243dSDimitry Andric SPIRV::Decoration::Decoration Dec, 12481ad6265SDimitry Andric const std::vector<uint32_t> &DecArgs, StringRef StrImm) { 12581ad6265SDimitry Andric MachineBasicBlock &MBB = *I.getParent(); 12681ad6265SDimitry Andric auto MIB = BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpDecorate)) 12781ad6265SDimitry Andric .addUse(Reg) 12881ad6265SDimitry Andric .addImm(static_cast<uint32_t>(Dec)); 12981ad6265SDimitry Andric finishBuildOpDecorate(MIB, DecArgs, StrImm); 13081ad6265SDimitry Andric } 13181ad6265SDimitry Andric 13281ad6265SDimitry Andric // TODO: maybe the following two functions should be handled in the subtarget 13381ad6265SDimitry Andric // to allow for different OpenCL vs Vulkan handling. 134bdd1243dSDimitry Andric unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC) { 13581ad6265SDimitry Andric switch (SC) { 13681ad6265SDimitry Andric case SPIRV::StorageClass::Function: 13781ad6265SDimitry Andric return 0; 13881ad6265SDimitry Andric case SPIRV::StorageClass::CrossWorkgroup: 13981ad6265SDimitry Andric return 1; 14081ad6265SDimitry Andric case SPIRV::StorageClass::UniformConstant: 14181ad6265SDimitry Andric return 2; 14281ad6265SDimitry Andric case SPIRV::StorageClass::Workgroup: 14381ad6265SDimitry Andric return 3; 14481ad6265SDimitry Andric case SPIRV::StorageClass::Generic: 14581ad6265SDimitry Andric return 4; 14681ad6265SDimitry Andric case SPIRV::StorageClass::Input: 14781ad6265SDimitry Andric return 7; 14881ad6265SDimitry Andric default: 14981ad6265SDimitry Andric llvm_unreachable("Unable to get address space id"); 15081ad6265SDimitry Andric } 15181ad6265SDimitry Andric } 15281ad6265SDimitry Andric 153bdd1243dSDimitry Andric SPIRV::StorageClass::StorageClass 154bdd1243dSDimitry Andric addressSpaceToStorageClass(unsigned AddrSpace) { 15581ad6265SDimitry Andric switch (AddrSpace) { 15681ad6265SDimitry Andric case 0: 15781ad6265SDimitry Andric return SPIRV::StorageClass::Function; 15881ad6265SDimitry Andric case 1: 15981ad6265SDimitry Andric return SPIRV::StorageClass::CrossWorkgroup; 16081ad6265SDimitry Andric case 2: 16181ad6265SDimitry Andric return SPIRV::StorageClass::UniformConstant; 16281ad6265SDimitry Andric case 3: 16381ad6265SDimitry Andric return SPIRV::StorageClass::Workgroup; 16481ad6265SDimitry Andric case 4: 16581ad6265SDimitry Andric return SPIRV::StorageClass::Generic; 16681ad6265SDimitry Andric case 7: 16781ad6265SDimitry Andric return SPIRV::StorageClass::Input; 16881ad6265SDimitry Andric default: 16981ad6265SDimitry Andric llvm_unreachable("Unknown address space"); 17081ad6265SDimitry Andric } 17181ad6265SDimitry Andric } 17281ad6265SDimitry Andric 173bdd1243dSDimitry Andric SPIRV::MemorySemantics::MemorySemantics 174bdd1243dSDimitry Andric getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC) { 17581ad6265SDimitry Andric switch (SC) { 17681ad6265SDimitry Andric case SPIRV::StorageClass::StorageBuffer: 17781ad6265SDimitry Andric case SPIRV::StorageClass::Uniform: 17881ad6265SDimitry Andric return SPIRV::MemorySemantics::UniformMemory; 17981ad6265SDimitry Andric case SPIRV::StorageClass::Workgroup: 18081ad6265SDimitry Andric return SPIRV::MemorySemantics::WorkgroupMemory; 18181ad6265SDimitry Andric case SPIRV::StorageClass::CrossWorkgroup: 18281ad6265SDimitry Andric return SPIRV::MemorySemantics::CrossWorkgroupMemory; 18381ad6265SDimitry Andric case SPIRV::StorageClass::AtomicCounter: 18481ad6265SDimitry Andric return SPIRV::MemorySemantics::AtomicCounterMemory; 18581ad6265SDimitry Andric case SPIRV::StorageClass::Image: 18681ad6265SDimitry Andric return SPIRV::MemorySemantics::ImageMemory; 18781ad6265SDimitry Andric default: 18881ad6265SDimitry Andric return SPIRV::MemorySemantics::None; 18981ad6265SDimitry Andric } 19081ad6265SDimitry Andric } 19181ad6265SDimitry Andric 192bdd1243dSDimitry Andric SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord) { 193fcaf7f86SDimitry Andric switch (Ord) { 194fcaf7f86SDimitry Andric case AtomicOrdering::Acquire: 195fcaf7f86SDimitry Andric return SPIRV::MemorySemantics::Acquire; 196fcaf7f86SDimitry Andric case AtomicOrdering::Release: 197fcaf7f86SDimitry Andric return SPIRV::MemorySemantics::Release; 198fcaf7f86SDimitry Andric case AtomicOrdering::AcquireRelease: 199fcaf7f86SDimitry Andric return SPIRV::MemorySemantics::AcquireRelease; 200fcaf7f86SDimitry Andric case AtomicOrdering::SequentiallyConsistent: 201fcaf7f86SDimitry Andric return SPIRV::MemorySemantics::SequentiallyConsistent; 202fcaf7f86SDimitry Andric case AtomicOrdering::Unordered: 203fcaf7f86SDimitry Andric case AtomicOrdering::Monotonic: 204fcaf7f86SDimitry Andric case AtomicOrdering::NotAtomic: 205fcaf7f86SDimitry Andric return SPIRV::MemorySemantics::None; 206fcaf7f86SDimitry Andric } 20706c3fb27SDimitry Andric llvm_unreachable(nullptr); 208fcaf7f86SDimitry Andric } 209fcaf7f86SDimitry Andric 21081ad6265SDimitry Andric MachineInstr *getDefInstrMaybeConstant(Register &ConstReg, 21181ad6265SDimitry Andric const MachineRegisterInfo *MRI) { 21281ad6265SDimitry Andric MachineInstr *ConstInstr = MRI->getVRegDef(ConstReg); 2135f757f3fSDimitry Andric if (auto *GI = dyn_cast<GIntrinsic>(ConstInstr)) { 2145f757f3fSDimitry Andric if (GI->is(Intrinsic::spv_track_constant)) { 21581ad6265SDimitry Andric ConstReg = ConstInstr->getOperand(2).getReg(); 2165f757f3fSDimitry Andric return MRI->getVRegDef(ConstReg); 2175f757f3fSDimitry Andric } 21881ad6265SDimitry Andric } else if (ConstInstr->getOpcode() == SPIRV::ASSIGN_TYPE) { 21981ad6265SDimitry Andric ConstReg = ConstInstr->getOperand(1).getReg(); 2205f757f3fSDimitry Andric return MRI->getVRegDef(ConstReg); 22181ad6265SDimitry Andric } 2225f757f3fSDimitry Andric return MRI->getVRegDef(ConstReg); 22381ad6265SDimitry Andric } 22481ad6265SDimitry Andric 22581ad6265SDimitry Andric uint64_t getIConstVal(Register ConstReg, const MachineRegisterInfo *MRI) { 22681ad6265SDimitry Andric const MachineInstr *MI = getDefInstrMaybeConstant(ConstReg, MRI); 22781ad6265SDimitry Andric assert(MI && MI->getOpcode() == TargetOpcode::G_CONSTANT); 22881ad6265SDimitry Andric return MI->getOperand(1).getCImm()->getValue().getZExtValue(); 22981ad6265SDimitry Andric } 23081ad6265SDimitry Andric 231*1db9f3b2SDimitry Andric bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID) { 232*1db9f3b2SDimitry Andric if (const auto *GI = dyn_cast<GIntrinsic>(&MI)) 2335f757f3fSDimitry Andric return GI->is(IntrinsicID); 2345f757f3fSDimitry Andric return false; 235fcaf7f86SDimitry Andric } 236fcaf7f86SDimitry Andric 23781ad6265SDimitry Andric Type *getMDOperandAsType(const MDNode *N, unsigned I) { 23881ad6265SDimitry Andric return cast<ValueAsMetadata>(N->getOperand(I))->getType(); 23981ad6265SDimitry Andric } 240bdd1243dSDimitry Andric 241bdd1243dSDimitry Andric // The set of names is borrowed from the SPIR-V translator. 242bdd1243dSDimitry Andric // TODO: may be implemented in SPIRVBuiltins.td. 243bdd1243dSDimitry Andric static bool isPipeOrAddressSpaceCastBI(const StringRef MangledName) { 244bdd1243dSDimitry Andric return MangledName == "write_pipe_2" || MangledName == "read_pipe_2" || 245bdd1243dSDimitry Andric MangledName == "write_pipe_2_bl" || MangledName == "read_pipe_2_bl" || 246bdd1243dSDimitry Andric MangledName == "write_pipe_4" || MangledName == "read_pipe_4" || 247bdd1243dSDimitry Andric MangledName == "reserve_write_pipe" || 248bdd1243dSDimitry Andric MangledName == "reserve_read_pipe" || 249bdd1243dSDimitry Andric MangledName == "commit_write_pipe" || 250bdd1243dSDimitry Andric MangledName == "commit_read_pipe" || 251bdd1243dSDimitry Andric MangledName == "work_group_reserve_write_pipe" || 252bdd1243dSDimitry Andric MangledName == "work_group_reserve_read_pipe" || 253bdd1243dSDimitry Andric MangledName == "work_group_commit_write_pipe" || 254bdd1243dSDimitry Andric MangledName == "work_group_commit_read_pipe" || 255bdd1243dSDimitry Andric MangledName == "get_pipe_num_packets_ro" || 256bdd1243dSDimitry Andric MangledName == "get_pipe_max_packets_ro" || 257bdd1243dSDimitry Andric MangledName == "get_pipe_num_packets_wo" || 258bdd1243dSDimitry Andric MangledName == "get_pipe_max_packets_wo" || 259bdd1243dSDimitry Andric MangledName == "sub_group_reserve_write_pipe" || 260bdd1243dSDimitry Andric MangledName == "sub_group_reserve_read_pipe" || 261bdd1243dSDimitry Andric MangledName == "sub_group_commit_write_pipe" || 262bdd1243dSDimitry Andric MangledName == "sub_group_commit_read_pipe" || 263bdd1243dSDimitry Andric MangledName == "to_global" || MangledName == "to_local" || 264bdd1243dSDimitry Andric MangledName == "to_private"; 265bdd1243dSDimitry Andric } 266bdd1243dSDimitry Andric 267bdd1243dSDimitry Andric static bool isEnqueueKernelBI(const StringRef MangledName) { 268bdd1243dSDimitry Andric return MangledName == "__enqueue_kernel_basic" || 269bdd1243dSDimitry Andric MangledName == "__enqueue_kernel_basic_events" || 270bdd1243dSDimitry Andric MangledName == "__enqueue_kernel_varargs" || 271bdd1243dSDimitry Andric MangledName == "__enqueue_kernel_events_varargs"; 272bdd1243dSDimitry Andric } 273bdd1243dSDimitry Andric 274bdd1243dSDimitry Andric static bool isKernelQueryBI(const StringRef MangledName) { 275bdd1243dSDimitry Andric return MangledName == "__get_kernel_work_group_size_impl" || 276bdd1243dSDimitry Andric MangledName == "__get_kernel_sub_group_count_for_ndrange_impl" || 277bdd1243dSDimitry Andric MangledName == "__get_kernel_max_sub_group_size_for_ndrange_impl" || 278bdd1243dSDimitry Andric MangledName == "__get_kernel_preferred_work_group_size_multiple_impl"; 279bdd1243dSDimitry Andric } 280bdd1243dSDimitry Andric 281bdd1243dSDimitry Andric static bool isNonMangledOCLBuiltin(StringRef Name) { 2825f757f3fSDimitry Andric if (!Name.starts_with("__")) 283bdd1243dSDimitry Andric return false; 284bdd1243dSDimitry Andric 285bdd1243dSDimitry Andric return isEnqueueKernelBI(Name) || isKernelQueryBI(Name) || 286bdd1243dSDimitry Andric isPipeOrAddressSpaceCastBI(Name.drop_front(2)) || 287bdd1243dSDimitry Andric Name == "__translate_sampler_initializer"; 288bdd1243dSDimitry Andric } 289bdd1243dSDimitry Andric 290bdd1243dSDimitry Andric std::string getOclOrSpirvBuiltinDemangledName(StringRef Name) { 291bdd1243dSDimitry Andric bool IsNonMangledOCL = isNonMangledOCLBuiltin(Name); 2925f757f3fSDimitry Andric bool IsNonMangledSPIRV = Name.starts_with("__spirv_"); 2935f757f3fSDimitry Andric bool IsMangled = Name.starts_with("_Z"); 294bdd1243dSDimitry Andric 295bdd1243dSDimitry Andric if (!IsNonMangledOCL && !IsNonMangledSPIRV && !IsMangled) 296bdd1243dSDimitry Andric return std::string(); 297bdd1243dSDimitry Andric 298bdd1243dSDimitry Andric // Try to use the itanium demangler. 29906c3fb27SDimitry Andric if (char *DemangledName = itaniumDemangle(Name.data())) { 300bdd1243dSDimitry Andric std::string Result = DemangledName; 301bdd1243dSDimitry Andric free(DemangledName); 302bdd1243dSDimitry Andric return Result; 303bdd1243dSDimitry Andric } 304bdd1243dSDimitry Andric // Otherwise use simple demangling to return the function name. 305bdd1243dSDimitry Andric if (IsNonMangledOCL || IsNonMangledSPIRV) 306bdd1243dSDimitry Andric return Name.str(); 307bdd1243dSDimitry Andric 308bdd1243dSDimitry Andric // Autocheck C++, maybe need to do explicit check of the source language. 309bdd1243dSDimitry Andric // OpenCL C++ built-ins are declared in cl namespace. 310bdd1243dSDimitry Andric // TODO: consider using 'St' abbriviation for cl namespace mangling. 311bdd1243dSDimitry Andric // Similar to ::std:: in C++. 312bdd1243dSDimitry Andric size_t Start, Len = 0; 313bdd1243dSDimitry Andric size_t DemangledNameLenStart = 2; 3145f757f3fSDimitry Andric if (Name.starts_with("_ZN")) { 315bdd1243dSDimitry Andric // Skip CV and ref qualifiers. 316bdd1243dSDimitry Andric size_t NameSpaceStart = Name.find_first_not_of("rVKRO", 3); 317bdd1243dSDimitry Andric // All built-ins are in the ::cl:: namespace. 318bdd1243dSDimitry Andric if (Name.substr(NameSpaceStart, 11) != "2cl7__spirv") 319bdd1243dSDimitry Andric return std::string(); 320bdd1243dSDimitry Andric DemangledNameLenStart = NameSpaceStart + 11; 321bdd1243dSDimitry Andric } 322bdd1243dSDimitry Andric Start = Name.find_first_not_of("0123456789", DemangledNameLenStart); 323bdd1243dSDimitry Andric Name.substr(DemangledNameLenStart, Start - DemangledNameLenStart) 324bdd1243dSDimitry Andric .getAsInteger(10, Len); 325bdd1243dSDimitry Andric return Name.substr(Start, Len).str(); 326bdd1243dSDimitry Andric } 327bdd1243dSDimitry Andric 328bdd1243dSDimitry Andric const Type *getTypedPtrEltType(const Type *Ty) { 3295f757f3fSDimitry Andric // TODO: This function requires updating following the opaque pointer 3305f757f3fSDimitry Andric // migration. 331bdd1243dSDimitry Andric return Ty; 332bdd1243dSDimitry Andric } 333bdd1243dSDimitry Andric 3345f757f3fSDimitry Andric bool hasBuiltinTypePrefix(StringRef Name) { 33506c3fb27SDimitry Andric if (Name.starts_with("opencl.") || Name.starts_with("spirv.")) 33606c3fb27SDimitry Andric return true; 33706c3fb27SDimitry Andric return false; 33806c3fb27SDimitry Andric } 33906c3fb27SDimitry Andric 340bdd1243dSDimitry Andric bool isSpecialOpaqueType(const Type *Ty) { 34106c3fb27SDimitry Andric const StructType *SType = dyn_cast<StructType>(getTypedPtrEltType(Ty)); 34206c3fb27SDimitry Andric if (SType && SType->hasName()) 34306c3fb27SDimitry Andric return hasBuiltinTypePrefix(SType->getName()); 34406c3fb27SDimitry Andric 34506c3fb27SDimitry Andric if (const TargetExtType *EType = 34606c3fb27SDimitry Andric dyn_cast<TargetExtType>(getTypedPtrEltType(Ty))) 34706c3fb27SDimitry Andric return hasBuiltinTypePrefix(EType->getName()); 34806c3fb27SDimitry Andric 349bdd1243dSDimitry Andric return false; 350bdd1243dSDimitry Andric } 351bdd1243dSDimitry Andric } // namespace llvm 352