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" 21bdd1243dSDimitry Andric #include "llvm/Demangle/Demangle.h" 2281ad6265SDimitry Andric #include "llvm/IR/IntrinsicsSPIRV.h" 2381ad6265SDimitry Andric 24bdd1243dSDimitry 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(); 80*06c3fb27SDimitry Andric if (Bitwidth == 1) 81*06c3fb27SDimitry Andric return; // Already handled 82*06c3fb27SDimitry Andric else if (Bitwidth <= 32) { 8381ad6265SDimitry Andric MIB.addImm(Imm.getZExtValue()); 84*06c3fb27SDimitry Andric return; 85*06c3fb27SDimitry Andric } else if (Bitwidth <= 64) { 8681ad6265SDimitry Andric uint64_t FullImm = Imm.getZExtValue(); 8781ad6265SDimitry Andric uint32_t LowBits = FullImm & 0xffffffff; 8881ad6265SDimitry Andric uint32_t HighBits = (FullImm >> 32) & 0xffffffff; 8981ad6265SDimitry Andric MIB.addImm(LowBits).addImm(HighBits); 90*06c3fb27SDimitry Andric return; 9181ad6265SDimitry Andric } 9281ad6265SDimitry Andric report_fatal_error("Unsupported constant bitwidth"); 9381ad6265SDimitry Andric } 9481ad6265SDimitry Andric 9581ad6265SDimitry Andric void buildOpName(Register Target, const StringRef &Name, 9681ad6265SDimitry Andric MachineIRBuilder &MIRBuilder) { 9781ad6265SDimitry Andric if (!Name.empty()) { 9881ad6265SDimitry Andric auto MIB = MIRBuilder.buildInstr(SPIRV::OpName).addUse(Target); 9981ad6265SDimitry Andric addStringImm(Name, MIB); 10081ad6265SDimitry Andric } 10181ad6265SDimitry Andric } 10281ad6265SDimitry Andric 10381ad6265SDimitry Andric static void finishBuildOpDecorate(MachineInstrBuilder &MIB, 10481ad6265SDimitry Andric const std::vector<uint32_t> &DecArgs, 10581ad6265SDimitry Andric StringRef StrImm) { 10681ad6265SDimitry Andric if (!StrImm.empty()) 10781ad6265SDimitry Andric addStringImm(StrImm, MIB); 10881ad6265SDimitry Andric for (const auto &DecArg : DecArgs) 10981ad6265SDimitry Andric MIB.addImm(DecArg); 11081ad6265SDimitry Andric } 11181ad6265SDimitry Andric 11281ad6265SDimitry Andric void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, 113bdd1243dSDimitry Andric SPIRV::Decoration::Decoration Dec, 11481ad6265SDimitry Andric const std::vector<uint32_t> &DecArgs, StringRef StrImm) { 11581ad6265SDimitry Andric auto MIB = MIRBuilder.buildInstr(SPIRV::OpDecorate) 11681ad6265SDimitry Andric .addUse(Reg) 11781ad6265SDimitry Andric .addImm(static_cast<uint32_t>(Dec)); 11881ad6265SDimitry Andric finishBuildOpDecorate(MIB, DecArgs, StrImm); 11981ad6265SDimitry Andric } 12081ad6265SDimitry Andric 12181ad6265SDimitry Andric void buildOpDecorate(Register Reg, MachineInstr &I, const SPIRVInstrInfo &TII, 122bdd1243dSDimitry Andric SPIRV::Decoration::Decoration Dec, 12381ad6265SDimitry Andric const std::vector<uint32_t> &DecArgs, StringRef StrImm) { 12481ad6265SDimitry Andric MachineBasicBlock &MBB = *I.getParent(); 12581ad6265SDimitry Andric auto MIB = BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpDecorate)) 12681ad6265SDimitry Andric .addUse(Reg) 12781ad6265SDimitry Andric .addImm(static_cast<uint32_t>(Dec)); 12881ad6265SDimitry Andric finishBuildOpDecorate(MIB, DecArgs, StrImm); 12981ad6265SDimitry Andric } 13081ad6265SDimitry Andric 13181ad6265SDimitry Andric // TODO: maybe the following two functions should be handled in the subtarget 13281ad6265SDimitry Andric // to allow for different OpenCL vs Vulkan handling. 133bdd1243dSDimitry Andric unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC) { 13481ad6265SDimitry Andric switch (SC) { 13581ad6265SDimitry Andric case SPIRV::StorageClass::Function: 13681ad6265SDimitry Andric return 0; 13781ad6265SDimitry Andric case SPIRV::StorageClass::CrossWorkgroup: 13881ad6265SDimitry Andric return 1; 13981ad6265SDimitry Andric case SPIRV::StorageClass::UniformConstant: 14081ad6265SDimitry Andric return 2; 14181ad6265SDimitry Andric case SPIRV::StorageClass::Workgroup: 14281ad6265SDimitry Andric return 3; 14381ad6265SDimitry Andric case SPIRV::StorageClass::Generic: 14481ad6265SDimitry Andric return 4; 14581ad6265SDimitry Andric case SPIRV::StorageClass::Input: 14681ad6265SDimitry Andric return 7; 14781ad6265SDimitry Andric default: 14881ad6265SDimitry Andric llvm_unreachable("Unable to get address space id"); 14981ad6265SDimitry Andric } 15081ad6265SDimitry Andric } 15181ad6265SDimitry Andric 152bdd1243dSDimitry Andric SPIRV::StorageClass::StorageClass 153bdd1243dSDimitry Andric addressSpaceToStorageClass(unsigned AddrSpace) { 15481ad6265SDimitry Andric switch (AddrSpace) { 15581ad6265SDimitry Andric case 0: 15681ad6265SDimitry Andric return SPIRV::StorageClass::Function; 15781ad6265SDimitry Andric case 1: 15881ad6265SDimitry Andric return SPIRV::StorageClass::CrossWorkgroup; 15981ad6265SDimitry Andric case 2: 16081ad6265SDimitry Andric return SPIRV::StorageClass::UniformConstant; 16181ad6265SDimitry Andric case 3: 16281ad6265SDimitry Andric return SPIRV::StorageClass::Workgroup; 16381ad6265SDimitry Andric case 4: 16481ad6265SDimitry Andric return SPIRV::StorageClass::Generic; 16581ad6265SDimitry Andric case 7: 16681ad6265SDimitry Andric return SPIRV::StorageClass::Input; 16781ad6265SDimitry Andric default: 16881ad6265SDimitry Andric llvm_unreachable("Unknown address space"); 16981ad6265SDimitry Andric } 17081ad6265SDimitry Andric } 17181ad6265SDimitry Andric 172bdd1243dSDimitry Andric SPIRV::MemorySemantics::MemorySemantics 173bdd1243dSDimitry Andric getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC) { 17481ad6265SDimitry Andric switch (SC) { 17581ad6265SDimitry Andric case SPIRV::StorageClass::StorageBuffer: 17681ad6265SDimitry Andric case SPIRV::StorageClass::Uniform: 17781ad6265SDimitry Andric return SPIRV::MemorySemantics::UniformMemory; 17881ad6265SDimitry Andric case SPIRV::StorageClass::Workgroup: 17981ad6265SDimitry Andric return SPIRV::MemorySemantics::WorkgroupMemory; 18081ad6265SDimitry Andric case SPIRV::StorageClass::CrossWorkgroup: 18181ad6265SDimitry Andric return SPIRV::MemorySemantics::CrossWorkgroupMemory; 18281ad6265SDimitry Andric case SPIRV::StorageClass::AtomicCounter: 18381ad6265SDimitry Andric return SPIRV::MemorySemantics::AtomicCounterMemory; 18481ad6265SDimitry Andric case SPIRV::StorageClass::Image: 18581ad6265SDimitry Andric return SPIRV::MemorySemantics::ImageMemory; 18681ad6265SDimitry Andric default: 18781ad6265SDimitry Andric return SPIRV::MemorySemantics::None; 18881ad6265SDimitry Andric } 18981ad6265SDimitry Andric } 19081ad6265SDimitry Andric 191bdd1243dSDimitry Andric SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord) { 192fcaf7f86SDimitry Andric switch (Ord) { 193fcaf7f86SDimitry Andric case AtomicOrdering::Acquire: 194fcaf7f86SDimitry Andric return SPIRV::MemorySemantics::Acquire; 195fcaf7f86SDimitry Andric case AtomicOrdering::Release: 196fcaf7f86SDimitry Andric return SPIRV::MemorySemantics::Release; 197fcaf7f86SDimitry Andric case AtomicOrdering::AcquireRelease: 198fcaf7f86SDimitry Andric return SPIRV::MemorySemantics::AcquireRelease; 199fcaf7f86SDimitry Andric case AtomicOrdering::SequentiallyConsistent: 200fcaf7f86SDimitry Andric return SPIRV::MemorySemantics::SequentiallyConsistent; 201fcaf7f86SDimitry Andric case AtomicOrdering::Unordered: 202fcaf7f86SDimitry Andric case AtomicOrdering::Monotonic: 203fcaf7f86SDimitry Andric case AtomicOrdering::NotAtomic: 204fcaf7f86SDimitry Andric return SPIRV::MemorySemantics::None; 205fcaf7f86SDimitry Andric } 206*06c3fb27SDimitry Andric llvm_unreachable(nullptr); 207fcaf7f86SDimitry Andric } 208fcaf7f86SDimitry Andric 20981ad6265SDimitry Andric MachineInstr *getDefInstrMaybeConstant(Register &ConstReg, 21081ad6265SDimitry Andric const MachineRegisterInfo *MRI) { 21181ad6265SDimitry Andric MachineInstr *ConstInstr = MRI->getVRegDef(ConstReg); 21281ad6265SDimitry Andric if (ConstInstr->getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS && 21381ad6265SDimitry Andric ConstInstr->getIntrinsicID() == Intrinsic::spv_track_constant) { 21481ad6265SDimitry Andric ConstReg = ConstInstr->getOperand(2).getReg(); 21581ad6265SDimitry Andric ConstInstr = MRI->getVRegDef(ConstReg); 21681ad6265SDimitry Andric } else if (ConstInstr->getOpcode() == SPIRV::ASSIGN_TYPE) { 21781ad6265SDimitry Andric ConstReg = ConstInstr->getOperand(1).getReg(); 21881ad6265SDimitry Andric ConstInstr = MRI->getVRegDef(ConstReg); 21981ad6265SDimitry Andric } 22081ad6265SDimitry Andric return ConstInstr; 22181ad6265SDimitry Andric } 22281ad6265SDimitry Andric 22381ad6265SDimitry Andric uint64_t getIConstVal(Register ConstReg, const MachineRegisterInfo *MRI) { 22481ad6265SDimitry Andric const MachineInstr *MI = getDefInstrMaybeConstant(ConstReg, MRI); 22581ad6265SDimitry Andric assert(MI && MI->getOpcode() == TargetOpcode::G_CONSTANT); 22681ad6265SDimitry Andric return MI->getOperand(1).getCImm()->getValue().getZExtValue(); 22781ad6265SDimitry Andric } 22881ad6265SDimitry Andric 229fcaf7f86SDimitry Andric bool isSpvIntrinsic(MachineInstr &MI, Intrinsic::ID IntrinsicID) { 230fcaf7f86SDimitry Andric return MI.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS && 231fcaf7f86SDimitry Andric MI.getIntrinsicID() == IntrinsicID; 232fcaf7f86SDimitry Andric } 233fcaf7f86SDimitry Andric 23481ad6265SDimitry Andric Type *getMDOperandAsType(const MDNode *N, unsigned I) { 23581ad6265SDimitry Andric return cast<ValueAsMetadata>(N->getOperand(I))->getType(); 23681ad6265SDimitry Andric } 237bdd1243dSDimitry Andric 238bdd1243dSDimitry Andric // The set of names is borrowed from the SPIR-V translator. 239bdd1243dSDimitry Andric // TODO: may be implemented in SPIRVBuiltins.td. 240bdd1243dSDimitry Andric static bool isPipeOrAddressSpaceCastBI(const StringRef MangledName) { 241bdd1243dSDimitry Andric return MangledName == "write_pipe_2" || MangledName == "read_pipe_2" || 242bdd1243dSDimitry Andric MangledName == "write_pipe_2_bl" || MangledName == "read_pipe_2_bl" || 243bdd1243dSDimitry Andric MangledName == "write_pipe_4" || MangledName == "read_pipe_4" || 244bdd1243dSDimitry Andric MangledName == "reserve_write_pipe" || 245bdd1243dSDimitry Andric MangledName == "reserve_read_pipe" || 246bdd1243dSDimitry Andric MangledName == "commit_write_pipe" || 247bdd1243dSDimitry Andric MangledName == "commit_read_pipe" || 248bdd1243dSDimitry Andric MangledName == "work_group_reserve_write_pipe" || 249bdd1243dSDimitry Andric MangledName == "work_group_reserve_read_pipe" || 250bdd1243dSDimitry Andric MangledName == "work_group_commit_write_pipe" || 251bdd1243dSDimitry Andric MangledName == "work_group_commit_read_pipe" || 252bdd1243dSDimitry Andric MangledName == "get_pipe_num_packets_ro" || 253bdd1243dSDimitry Andric MangledName == "get_pipe_max_packets_ro" || 254bdd1243dSDimitry Andric MangledName == "get_pipe_num_packets_wo" || 255bdd1243dSDimitry Andric MangledName == "get_pipe_max_packets_wo" || 256bdd1243dSDimitry Andric MangledName == "sub_group_reserve_write_pipe" || 257bdd1243dSDimitry Andric MangledName == "sub_group_reserve_read_pipe" || 258bdd1243dSDimitry Andric MangledName == "sub_group_commit_write_pipe" || 259bdd1243dSDimitry Andric MangledName == "sub_group_commit_read_pipe" || 260bdd1243dSDimitry Andric MangledName == "to_global" || MangledName == "to_local" || 261bdd1243dSDimitry Andric MangledName == "to_private"; 262bdd1243dSDimitry Andric } 263bdd1243dSDimitry Andric 264bdd1243dSDimitry Andric static bool isEnqueueKernelBI(const StringRef MangledName) { 265bdd1243dSDimitry Andric return MangledName == "__enqueue_kernel_basic" || 266bdd1243dSDimitry Andric MangledName == "__enqueue_kernel_basic_events" || 267bdd1243dSDimitry Andric MangledName == "__enqueue_kernel_varargs" || 268bdd1243dSDimitry Andric MangledName == "__enqueue_kernel_events_varargs"; 269bdd1243dSDimitry Andric } 270bdd1243dSDimitry Andric 271bdd1243dSDimitry Andric static bool isKernelQueryBI(const StringRef MangledName) { 272bdd1243dSDimitry Andric return MangledName == "__get_kernel_work_group_size_impl" || 273bdd1243dSDimitry Andric MangledName == "__get_kernel_sub_group_count_for_ndrange_impl" || 274bdd1243dSDimitry Andric MangledName == "__get_kernel_max_sub_group_size_for_ndrange_impl" || 275bdd1243dSDimitry Andric MangledName == "__get_kernel_preferred_work_group_size_multiple_impl"; 276bdd1243dSDimitry Andric } 277bdd1243dSDimitry Andric 278bdd1243dSDimitry Andric static bool isNonMangledOCLBuiltin(StringRef Name) { 279bdd1243dSDimitry Andric if (!Name.startswith("__")) 280bdd1243dSDimitry Andric return false; 281bdd1243dSDimitry Andric 282bdd1243dSDimitry Andric return isEnqueueKernelBI(Name) || isKernelQueryBI(Name) || 283bdd1243dSDimitry Andric isPipeOrAddressSpaceCastBI(Name.drop_front(2)) || 284bdd1243dSDimitry Andric Name == "__translate_sampler_initializer"; 285bdd1243dSDimitry Andric } 286bdd1243dSDimitry Andric 287bdd1243dSDimitry Andric std::string getOclOrSpirvBuiltinDemangledName(StringRef Name) { 288bdd1243dSDimitry Andric bool IsNonMangledOCL = isNonMangledOCLBuiltin(Name); 289bdd1243dSDimitry Andric bool IsNonMangledSPIRV = Name.startswith("__spirv_"); 290bdd1243dSDimitry Andric bool IsMangled = Name.startswith("_Z"); 291bdd1243dSDimitry Andric 292bdd1243dSDimitry Andric if (!IsNonMangledOCL && !IsNonMangledSPIRV && !IsMangled) 293bdd1243dSDimitry Andric return std::string(); 294bdd1243dSDimitry Andric 295bdd1243dSDimitry Andric // Try to use the itanium demangler. 296*06c3fb27SDimitry Andric if (char *DemangledName = itaniumDemangle(Name.data())) { 297bdd1243dSDimitry Andric std::string Result = DemangledName; 298bdd1243dSDimitry Andric free(DemangledName); 299bdd1243dSDimitry Andric return Result; 300bdd1243dSDimitry Andric } 301bdd1243dSDimitry Andric // Otherwise use simple demangling to return the function name. 302bdd1243dSDimitry Andric if (IsNonMangledOCL || IsNonMangledSPIRV) 303bdd1243dSDimitry Andric return Name.str(); 304bdd1243dSDimitry Andric 305bdd1243dSDimitry Andric // Autocheck C++, maybe need to do explicit check of the source language. 306bdd1243dSDimitry Andric // OpenCL C++ built-ins are declared in cl namespace. 307bdd1243dSDimitry Andric // TODO: consider using 'St' abbriviation for cl namespace mangling. 308bdd1243dSDimitry Andric // Similar to ::std:: in C++. 309bdd1243dSDimitry Andric size_t Start, Len = 0; 310bdd1243dSDimitry Andric size_t DemangledNameLenStart = 2; 311bdd1243dSDimitry Andric if (Name.startswith("_ZN")) { 312bdd1243dSDimitry Andric // Skip CV and ref qualifiers. 313bdd1243dSDimitry Andric size_t NameSpaceStart = Name.find_first_not_of("rVKRO", 3); 314bdd1243dSDimitry Andric // All built-ins are in the ::cl:: namespace. 315bdd1243dSDimitry Andric if (Name.substr(NameSpaceStart, 11) != "2cl7__spirv") 316bdd1243dSDimitry Andric return std::string(); 317bdd1243dSDimitry Andric DemangledNameLenStart = NameSpaceStart + 11; 318bdd1243dSDimitry Andric } 319bdd1243dSDimitry Andric Start = Name.find_first_not_of("0123456789", DemangledNameLenStart); 320bdd1243dSDimitry Andric Name.substr(DemangledNameLenStart, Start - DemangledNameLenStart) 321bdd1243dSDimitry Andric .getAsInteger(10, Len); 322bdd1243dSDimitry Andric return Name.substr(Start, Len).str(); 323bdd1243dSDimitry Andric } 324bdd1243dSDimitry Andric 325bdd1243dSDimitry Andric const Type *getTypedPtrEltType(const Type *Ty) { 326bdd1243dSDimitry Andric auto PType = dyn_cast<PointerType>(Ty); 327bdd1243dSDimitry Andric if (!PType || PType->isOpaque()) 328bdd1243dSDimitry Andric return Ty; 329bdd1243dSDimitry Andric return PType->getNonOpaquePointerElementType(); 330bdd1243dSDimitry Andric } 331bdd1243dSDimitry Andric 332*06c3fb27SDimitry Andric static bool hasBuiltinTypePrefix(StringRef Name) { 333*06c3fb27SDimitry Andric if (Name.starts_with("opencl.") || Name.starts_with("spirv.")) 334*06c3fb27SDimitry Andric return true; 335*06c3fb27SDimitry Andric return false; 336*06c3fb27SDimitry Andric } 337*06c3fb27SDimitry Andric 338bdd1243dSDimitry Andric bool isSpecialOpaqueType(const Type *Ty) { 339*06c3fb27SDimitry Andric const StructType *SType = dyn_cast<StructType>(getTypedPtrEltType(Ty)); 340*06c3fb27SDimitry Andric if (SType && SType->hasName()) 341*06c3fb27SDimitry Andric return hasBuiltinTypePrefix(SType->getName()); 342*06c3fb27SDimitry Andric 343*06c3fb27SDimitry Andric if (const TargetExtType *EType = 344*06c3fb27SDimitry Andric dyn_cast<TargetExtType>(getTypedPtrEltType(Ty))) 345*06c3fb27SDimitry Andric return hasBuiltinTypePrefix(EType->getName()); 346*06c3fb27SDimitry Andric 347bdd1243dSDimitry Andric return false; 348bdd1243dSDimitry Andric } 349bdd1243dSDimitry Andric } // namespace llvm 350