xref: /openbsd-src/gnu/llvm/llvm/lib/Target/SPIRV/SPIRVUtils.cpp (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
1*d415bd75Srobert //===--- SPIRVUtils.cpp ---- SPIR-V Utility Functions -----------*- C++ -*-===//
2*d415bd75Srobert //
3*d415bd75Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*d415bd75Srobert // See https://llvm.org/LICENSE.txt for license information.
5*d415bd75Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*d415bd75Srobert //
7*d415bd75Srobert //===----------------------------------------------------------------------===//
8*d415bd75Srobert //
9*d415bd75Srobert // This file contains miscellaneous utility functions.
10*d415bd75Srobert //
11*d415bd75Srobert //===----------------------------------------------------------------------===//
12*d415bd75Srobert 
13*d415bd75Srobert #include "SPIRVUtils.h"
14*d415bd75Srobert #include "MCTargetDesc/SPIRVBaseInfo.h"
15*d415bd75Srobert #include "SPIRV.h"
16*d415bd75Srobert #include "SPIRVInstrInfo.h"
17*d415bd75Srobert #include "llvm/ADT/StringRef.h"
18*d415bd75Srobert #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
19*d415bd75Srobert #include "llvm/CodeGen/MachineInstr.h"
20*d415bd75Srobert #include "llvm/CodeGen/MachineInstrBuilder.h"
21*d415bd75Srobert #include "llvm/Demangle/Demangle.h"
22*d415bd75Srobert #include "llvm/IR/IntrinsicsSPIRV.h"
23*d415bd75Srobert 
24*d415bd75Srobert namespace llvm {
25*d415bd75Srobert 
26*d415bd75Srobert // The following functions are used to add these string literals as a series of
27*d415bd75Srobert // 32-bit integer operands with the correct format, and unpack them if necessary
28*d415bd75Srobert // when making string comparisons in compiler passes.
29*d415bd75Srobert // SPIR-V requires null-terminated UTF-8 strings padded to 32-bit alignment.
convertCharsToWord(const StringRef & Str,unsigned i)30*d415bd75Srobert static uint32_t convertCharsToWord(const StringRef &Str, unsigned i) {
31*d415bd75Srobert   uint32_t Word = 0u; // Build up this 32-bit word from 4 8-bit chars.
32*d415bd75Srobert   for (unsigned WordIndex = 0; WordIndex < 4; ++WordIndex) {
33*d415bd75Srobert     unsigned StrIndex = i + WordIndex;
34*d415bd75Srobert     uint8_t CharToAdd = 0;       // Initilize char as padding/null.
35*d415bd75Srobert     if (StrIndex < Str.size()) { // If it's within the string, get a real char.
36*d415bd75Srobert       CharToAdd = Str[StrIndex];
37*d415bd75Srobert     }
38*d415bd75Srobert     Word |= (CharToAdd << (WordIndex * 8));
39*d415bd75Srobert   }
40*d415bd75Srobert   return Word;
41*d415bd75Srobert }
42*d415bd75Srobert 
43*d415bd75Srobert // Get length including padding and null terminator.
getPaddedLen(const StringRef & Str)44*d415bd75Srobert static size_t getPaddedLen(const StringRef &Str) {
45*d415bd75Srobert   const size_t Len = Str.size() + 1;
46*d415bd75Srobert   return (Len % 4 == 0) ? Len : Len + (4 - (Len % 4));
47*d415bd75Srobert }
48*d415bd75Srobert 
addStringImm(const StringRef & Str,MCInst & Inst)49*d415bd75Srobert void addStringImm(const StringRef &Str, MCInst &Inst) {
50*d415bd75Srobert   const size_t PaddedLen = getPaddedLen(Str);
51*d415bd75Srobert   for (unsigned i = 0; i < PaddedLen; i += 4) {
52*d415bd75Srobert     // Add an operand for the 32-bits of chars or padding.
53*d415bd75Srobert     Inst.addOperand(MCOperand::createImm(convertCharsToWord(Str, i)));
54*d415bd75Srobert   }
55*d415bd75Srobert }
56*d415bd75Srobert 
addStringImm(const StringRef & Str,MachineInstrBuilder & MIB)57*d415bd75Srobert void addStringImm(const StringRef &Str, MachineInstrBuilder &MIB) {
58*d415bd75Srobert   const size_t PaddedLen = getPaddedLen(Str);
59*d415bd75Srobert   for (unsigned i = 0; i < PaddedLen; i += 4) {
60*d415bd75Srobert     // Add an operand for the 32-bits of chars or padding.
61*d415bd75Srobert     MIB.addImm(convertCharsToWord(Str, i));
62*d415bd75Srobert   }
63*d415bd75Srobert }
64*d415bd75Srobert 
addStringImm(const StringRef & Str,IRBuilder<> & B,std::vector<Value * > & Args)65*d415bd75Srobert void addStringImm(const StringRef &Str, IRBuilder<> &B,
66*d415bd75Srobert                   std::vector<Value *> &Args) {
67*d415bd75Srobert   const size_t PaddedLen = getPaddedLen(Str);
68*d415bd75Srobert   for (unsigned i = 0; i < PaddedLen; i += 4) {
69*d415bd75Srobert     // Add a vector element for the 32-bits of chars or padding.
70*d415bd75Srobert     Args.push_back(B.getInt32(convertCharsToWord(Str, i)));
71*d415bd75Srobert   }
72*d415bd75Srobert }
73*d415bd75Srobert 
getStringImm(const MachineInstr & MI,unsigned StartIndex)74*d415bd75Srobert std::string getStringImm(const MachineInstr &MI, unsigned StartIndex) {
75*d415bd75Srobert   return getSPIRVStringOperand(MI, StartIndex);
76*d415bd75Srobert }
77*d415bd75Srobert 
addNumImm(const APInt & Imm,MachineInstrBuilder & MIB)78*d415bd75Srobert void addNumImm(const APInt &Imm, MachineInstrBuilder &MIB) {
79*d415bd75Srobert   const auto Bitwidth = Imm.getBitWidth();
80*d415bd75Srobert   switch (Bitwidth) {
81*d415bd75Srobert   case 1:
82*d415bd75Srobert     break; // Already handled.
83*d415bd75Srobert   case 8:
84*d415bd75Srobert   case 16:
85*d415bd75Srobert   case 32:
86*d415bd75Srobert     MIB.addImm(Imm.getZExtValue());
87*d415bd75Srobert     break;
88*d415bd75Srobert   case 64: {
89*d415bd75Srobert     uint64_t FullImm = Imm.getZExtValue();
90*d415bd75Srobert     uint32_t LowBits = FullImm & 0xffffffff;
91*d415bd75Srobert     uint32_t HighBits = (FullImm >> 32) & 0xffffffff;
92*d415bd75Srobert     MIB.addImm(LowBits).addImm(HighBits);
93*d415bd75Srobert     break;
94*d415bd75Srobert   }
95*d415bd75Srobert   default:
96*d415bd75Srobert     report_fatal_error("Unsupported constant bitwidth");
97*d415bd75Srobert   }
98*d415bd75Srobert }
99*d415bd75Srobert 
buildOpName(Register Target,const StringRef & Name,MachineIRBuilder & MIRBuilder)100*d415bd75Srobert void buildOpName(Register Target, const StringRef &Name,
101*d415bd75Srobert                  MachineIRBuilder &MIRBuilder) {
102*d415bd75Srobert   if (!Name.empty()) {
103*d415bd75Srobert     auto MIB = MIRBuilder.buildInstr(SPIRV::OpName).addUse(Target);
104*d415bd75Srobert     addStringImm(Name, MIB);
105*d415bd75Srobert   }
106*d415bd75Srobert }
107*d415bd75Srobert 
finishBuildOpDecorate(MachineInstrBuilder & MIB,const std::vector<uint32_t> & DecArgs,StringRef StrImm)108*d415bd75Srobert static void finishBuildOpDecorate(MachineInstrBuilder &MIB,
109*d415bd75Srobert                                   const std::vector<uint32_t> &DecArgs,
110*d415bd75Srobert                                   StringRef StrImm) {
111*d415bd75Srobert   if (!StrImm.empty())
112*d415bd75Srobert     addStringImm(StrImm, MIB);
113*d415bd75Srobert   for (const auto &DecArg : DecArgs)
114*d415bd75Srobert     MIB.addImm(DecArg);
115*d415bd75Srobert }
116*d415bd75Srobert 
buildOpDecorate(Register Reg,MachineIRBuilder & MIRBuilder,SPIRV::Decoration::Decoration Dec,const std::vector<uint32_t> & DecArgs,StringRef StrImm)117*d415bd75Srobert void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder,
118*d415bd75Srobert                      SPIRV::Decoration::Decoration Dec,
119*d415bd75Srobert                      const std::vector<uint32_t> &DecArgs, StringRef StrImm) {
120*d415bd75Srobert   auto MIB = MIRBuilder.buildInstr(SPIRV::OpDecorate)
121*d415bd75Srobert                  .addUse(Reg)
122*d415bd75Srobert                  .addImm(static_cast<uint32_t>(Dec));
123*d415bd75Srobert   finishBuildOpDecorate(MIB, DecArgs, StrImm);
124*d415bd75Srobert }
125*d415bd75Srobert 
buildOpDecorate(Register Reg,MachineInstr & I,const SPIRVInstrInfo & TII,SPIRV::Decoration::Decoration Dec,const std::vector<uint32_t> & DecArgs,StringRef StrImm)126*d415bd75Srobert void buildOpDecorate(Register Reg, MachineInstr &I, const SPIRVInstrInfo &TII,
127*d415bd75Srobert                      SPIRV::Decoration::Decoration Dec,
128*d415bd75Srobert                      const std::vector<uint32_t> &DecArgs, StringRef StrImm) {
129*d415bd75Srobert   MachineBasicBlock &MBB = *I.getParent();
130*d415bd75Srobert   auto MIB = BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpDecorate))
131*d415bd75Srobert                  .addUse(Reg)
132*d415bd75Srobert                  .addImm(static_cast<uint32_t>(Dec));
133*d415bd75Srobert   finishBuildOpDecorate(MIB, DecArgs, StrImm);
134*d415bd75Srobert }
135*d415bd75Srobert 
136*d415bd75Srobert // TODO: maybe the following two functions should be handled in the subtarget
137*d415bd75Srobert // to allow for different OpenCL vs Vulkan handling.
storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC)138*d415bd75Srobert unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC) {
139*d415bd75Srobert   switch (SC) {
140*d415bd75Srobert   case SPIRV::StorageClass::Function:
141*d415bd75Srobert     return 0;
142*d415bd75Srobert   case SPIRV::StorageClass::CrossWorkgroup:
143*d415bd75Srobert     return 1;
144*d415bd75Srobert   case SPIRV::StorageClass::UniformConstant:
145*d415bd75Srobert     return 2;
146*d415bd75Srobert   case SPIRV::StorageClass::Workgroup:
147*d415bd75Srobert     return 3;
148*d415bd75Srobert   case SPIRV::StorageClass::Generic:
149*d415bd75Srobert     return 4;
150*d415bd75Srobert   case SPIRV::StorageClass::Input:
151*d415bd75Srobert     return 7;
152*d415bd75Srobert   default:
153*d415bd75Srobert     llvm_unreachable("Unable to get address space id");
154*d415bd75Srobert   }
155*d415bd75Srobert }
156*d415bd75Srobert 
157*d415bd75Srobert SPIRV::StorageClass::StorageClass
addressSpaceToStorageClass(unsigned AddrSpace)158*d415bd75Srobert addressSpaceToStorageClass(unsigned AddrSpace) {
159*d415bd75Srobert   switch (AddrSpace) {
160*d415bd75Srobert   case 0:
161*d415bd75Srobert     return SPIRV::StorageClass::Function;
162*d415bd75Srobert   case 1:
163*d415bd75Srobert     return SPIRV::StorageClass::CrossWorkgroup;
164*d415bd75Srobert   case 2:
165*d415bd75Srobert     return SPIRV::StorageClass::UniformConstant;
166*d415bd75Srobert   case 3:
167*d415bd75Srobert     return SPIRV::StorageClass::Workgroup;
168*d415bd75Srobert   case 4:
169*d415bd75Srobert     return SPIRV::StorageClass::Generic;
170*d415bd75Srobert   case 7:
171*d415bd75Srobert     return SPIRV::StorageClass::Input;
172*d415bd75Srobert   default:
173*d415bd75Srobert     llvm_unreachable("Unknown address space");
174*d415bd75Srobert   }
175*d415bd75Srobert }
176*d415bd75Srobert 
177*d415bd75Srobert SPIRV::MemorySemantics::MemorySemantics
getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC)178*d415bd75Srobert getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC) {
179*d415bd75Srobert   switch (SC) {
180*d415bd75Srobert   case SPIRV::StorageClass::StorageBuffer:
181*d415bd75Srobert   case SPIRV::StorageClass::Uniform:
182*d415bd75Srobert     return SPIRV::MemorySemantics::UniformMemory;
183*d415bd75Srobert   case SPIRV::StorageClass::Workgroup:
184*d415bd75Srobert     return SPIRV::MemorySemantics::WorkgroupMemory;
185*d415bd75Srobert   case SPIRV::StorageClass::CrossWorkgroup:
186*d415bd75Srobert     return SPIRV::MemorySemantics::CrossWorkgroupMemory;
187*d415bd75Srobert   case SPIRV::StorageClass::AtomicCounter:
188*d415bd75Srobert     return SPIRV::MemorySemantics::AtomicCounterMemory;
189*d415bd75Srobert   case SPIRV::StorageClass::Image:
190*d415bd75Srobert     return SPIRV::MemorySemantics::ImageMemory;
191*d415bd75Srobert   default:
192*d415bd75Srobert     return SPIRV::MemorySemantics::None;
193*d415bd75Srobert   }
194*d415bd75Srobert }
195*d415bd75Srobert 
getMemSemantics(AtomicOrdering Ord)196*d415bd75Srobert SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord) {
197*d415bd75Srobert   switch (Ord) {
198*d415bd75Srobert   case AtomicOrdering::Acquire:
199*d415bd75Srobert     return SPIRV::MemorySemantics::Acquire;
200*d415bd75Srobert   case AtomicOrdering::Release:
201*d415bd75Srobert     return SPIRV::MemorySemantics::Release;
202*d415bd75Srobert   case AtomicOrdering::AcquireRelease:
203*d415bd75Srobert     return SPIRV::MemorySemantics::AcquireRelease;
204*d415bd75Srobert   case AtomicOrdering::SequentiallyConsistent:
205*d415bd75Srobert     return SPIRV::MemorySemantics::SequentiallyConsistent;
206*d415bd75Srobert   case AtomicOrdering::Unordered:
207*d415bd75Srobert   case AtomicOrdering::Monotonic:
208*d415bd75Srobert   case AtomicOrdering::NotAtomic:
209*d415bd75Srobert   default:
210*d415bd75Srobert     return SPIRV::MemorySemantics::None;
211*d415bd75Srobert   }
212*d415bd75Srobert }
213*d415bd75Srobert 
getDefInstrMaybeConstant(Register & ConstReg,const MachineRegisterInfo * MRI)214*d415bd75Srobert MachineInstr *getDefInstrMaybeConstant(Register &ConstReg,
215*d415bd75Srobert                                        const MachineRegisterInfo *MRI) {
216*d415bd75Srobert   MachineInstr *ConstInstr = MRI->getVRegDef(ConstReg);
217*d415bd75Srobert   if (ConstInstr->getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS &&
218*d415bd75Srobert       ConstInstr->getIntrinsicID() == Intrinsic::spv_track_constant) {
219*d415bd75Srobert     ConstReg = ConstInstr->getOperand(2).getReg();
220*d415bd75Srobert     ConstInstr = MRI->getVRegDef(ConstReg);
221*d415bd75Srobert   } else if (ConstInstr->getOpcode() == SPIRV::ASSIGN_TYPE) {
222*d415bd75Srobert     ConstReg = ConstInstr->getOperand(1).getReg();
223*d415bd75Srobert     ConstInstr = MRI->getVRegDef(ConstReg);
224*d415bd75Srobert   }
225*d415bd75Srobert   return ConstInstr;
226*d415bd75Srobert }
227*d415bd75Srobert 
getIConstVal(Register ConstReg,const MachineRegisterInfo * MRI)228*d415bd75Srobert uint64_t getIConstVal(Register ConstReg, const MachineRegisterInfo *MRI) {
229*d415bd75Srobert   const MachineInstr *MI = getDefInstrMaybeConstant(ConstReg, MRI);
230*d415bd75Srobert   assert(MI && MI->getOpcode() == TargetOpcode::G_CONSTANT);
231*d415bd75Srobert   return MI->getOperand(1).getCImm()->getValue().getZExtValue();
232*d415bd75Srobert }
233*d415bd75Srobert 
isSpvIntrinsic(MachineInstr & MI,Intrinsic::ID IntrinsicID)234*d415bd75Srobert bool isSpvIntrinsic(MachineInstr &MI, Intrinsic::ID IntrinsicID) {
235*d415bd75Srobert   return MI.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS &&
236*d415bd75Srobert          MI.getIntrinsicID() == IntrinsicID;
237*d415bd75Srobert }
238*d415bd75Srobert 
getMDOperandAsType(const MDNode * N,unsigned I)239*d415bd75Srobert Type *getMDOperandAsType(const MDNode *N, unsigned I) {
240*d415bd75Srobert   return cast<ValueAsMetadata>(N->getOperand(I))->getType();
241*d415bd75Srobert }
242*d415bd75Srobert 
243*d415bd75Srobert // The set of names is borrowed from the SPIR-V translator.
244*d415bd75Srobert // TODO: may be implemented in SPIRVBuiltins.td.
isPipeOrAddressSpaceCastBI(const StringRef MangledName)245*d415bd75Srobert static bool isPipeOrAddressSpaceCastBI(const StringRef MangledName) {
246*d415bd75Srobert   return MangledName == "write_pipe_2" || MangledName == "read_pipe_2" ||
247*d415bd75Srobert          MangledName == "write_pipe_2_bl" || MangledName == "read_pipe_2_bl" ||
248*d415bd75Srobert          MangledName == "write_pipe_4" || MangledName == "read_pipe_4" ||
249*d415bd75Srobert          MangledName == "reserve_write_pipe" ||
250*d415bd75Srobert          MangledName == "reserve_read_pipe" ||
251*d415bd75Srobert          MangledName == "commit_write_pipe" ||
252*d415bd75Srobert          MangledName == "commit_read_pipe" ||
253*d415bd75Srobert          MangledName == "work_group_reserve_write_pipe" ||
254*d415bd75Srobert          MangledName == "work_group_reserve_read_pipe" ||
255*d415bd75Srobert          MangledName == "work_group_commit_write_pipe" ||
256*d415bd75Srobert          MangledName == "work_group_commit_read_pipe" ||
257*d415bd75Srobert          MangledName == "get_pipe_num_packets_ro" ||
258*d415bd75Srobert          MangledName == "get_pipe_max_packets_ro" ||
259*d415bd75Srobert          MangledName == "get_pipe_num_packets_wo" ||
260*d415bd75Srobert          MangledName == "get_pipe_max_packets_wo" ||
261*d415bd75Srobert          MangledName == "sub_group_reserve_write_pipe" ||
262*d415bd75Srobert          MangledName == "sub_group_reserve_read_pipe" ||
263*d415bd75Srobert          MangledName == "sub_group_commit_write_pipe" ||
264*d415bd75Srobert          MangledName == "sub_group_commit_read_pipe" ||
265*d415bd75Srobert          MangledName == "to_global" || MangledName == "to_local" ||
266*d415bd75Srobert          MangledName == "to_private";
267*d415bd75Srobert }
268*d415bd75Srobert 
isEnqueueKernelBI(const StringRef MangledName)269*d415bd75Srobert static bool isEnqueueKernelBI(const StringRef MangledName) {
270*d415bd75Srobert   return MangledName == "__enqueue_kernel_basic" ||
271*d415bd75Srobert          MangledName == "__enqueue_kernel_basic_events" ||
272*d415bd75Srobert          MangledName == "__enqueue_kernel_varargs" ||
273*d415bd75Srobert          MangledName == "__enqueue_kernel_events_varargs";
274*d415bd75Srobert }
275*d415bd75Srobert 
isKernelQueryBI(const StringRef MangledName)276*d415bd75Srobert static bool isKernelQueryBI(const StringRef MangledName) {
277*d415bd75Srobert   return MangledName == "__get_kernel_work_group_size_impl" ||
278*d415bd75Srobert          MangledName == "__get_kernel_sub_group_count_for_ndrange_impl" ||
279*d415bd75Srobert          MangledName == "__get_kernel_max_sub_group_size_for_ndrange_impl" ||
280*d415bd75Srobert          MangledName == "__get_kernel_preferred_work_group_size_multiple_impl";
281*d415bd75Srobert }
282*d415bd75Srobert 
isNonMangledOCLBuiltin(StringRef Name)283*d415bd75Srobert static bool isNonMangledOCLBuiltin(StringRef Name) {
284*d415bd75Srobert   if (!Name.startswith("__"))
285*d415bd75Srobert     return false;
286*d415bd75Srobert 
287*d415bd75Srobert   return isEnqueueKernelBI(Name) || isKernelQueryBI(Name) ||
288*d415bd75Srobert          isPipeOrAddressSpaceCastBI(Name.drop_front(2)) ||
289*d415bd75Srobert          Name == "__translate_sampler_initializer";
290*d415bd75Srobert }
291*d415bd75Srobert 
getOclOrSpirvBuiltinDemangledName(StringRef Name)292*d415bd75Srobert std::string getOclOrSpirvBuiltinDemangledName(StringRef Name) {
293*d415bd75Srobert   bool IsNonMangledOCL = isNonMangledOCLBuiltin(Name);
294*d415bd75Srobert   bool IsNonMangledSPIRV = Name.startswith("__spirv_");
295*d415bd75Srobert   bool IsMangled = Name.startswith("_Z");
296*d415bd75Srobert 
297*d415bd75Srobert   if (!IsNonMangledOCL && !IsNonMangledSPIRV && !IsMangled)
298*d415bd75Srobert     return std::string();
299*d415bd75Srobert 
300*d415bd75Srobert   // Try to use the itanium demangler.
301*d415bd75Srobert   size_t n;
302*d415bd75Srobert   int Status;
303*d415bd75Srobert   char *DemangledName = itaniumDemangle(Name.data(), nullptr, &n, &Status);
304*d415bd75Srobert 
305*d415bd75Srobert   if (Status == demangle_success) {
306*d415bd75Srobert     std::string Result = DemangledName;
307*d415bd75Srobert     free(DemangledName);
308*d415bd75Srobert     return Result;
309*d415bd75Srobert   }
310*d415bd75Srobert   free(DemangledName);
311*d415bd75Srobert   // Otherwise use simple demangling to return the function name.
312*d415bd75Srobert   if (IsNonMangledOCL || IsNonMangledSPIRV)
313*d415bd75Srobert     return Name.str();
314*d415bd75Srobert 
315*d415bd75Srobert   // Autocheck C++, maybe need to do explicit check of the source language.
316*d415bd75Srobert   // OpenCL C++ built-ins are declared in cl namespace.
317*d415bd75Srobert   // TODO: consider using 'St' abbriviation for cl namespace mangling.
318*d415bd75Srobert   // Similar to ::std:: in C++.
319*d415bd75Srobert   size_t Start, Len = 0;
320*d415bd75Srobert   size_t DemangledNameLenStart = 2;
321*d415bd75Srobert   if (Name.startswith("_ZN")) {
322*d415bd75Srobert     // Skip CV and ref qualifiers.
323*d415bd75Srobert     size_t NameSpaceStart = Name.find_first_not_of("rVKRO", 3);
324*d415bd75Srobert     // All built-ins are in the ::cl:: namespace.
325*d415bd75Srobert     if (Name.substr(NameSpaceStart, 11) != "2cl7__spirv")
326*d415bd75Srobert       return std::string();
327*d415bd75Srobert     DemangledNameLenStart = NameSpaceStart + 11;
328*d415bd75Srobert   }
329*d415bd75Srobert   Start = Name.find_first_not_of("0123456789", DemangledNameLenStart);
330*d415bd75Srobert   Name.substr(DemangledNameLenStart, Start - DemangledNameLenStart)
331*d415bd75Srobert       .getAsInteger(10, Len);
332*d415bd75Srobert   return Name.substr(Start, Len).str();
333*d415bd75Srobert }
334*d415bd75Srobert 
isOpenCLBuiltinType(const StructType * SType)335*d415bd75Srobert static bool isOpenCLBuiltinType(const StructType *SType) {
336*d415bd75Srobert   return SType->isOpaque() && SType->hasName() &&
337*d415bd75Srobert          SType->getName().startswith("opencl.");
338*d415bd75Srobert }
339*d415bd75Srobert 
isSPIRVBuiltinType(const StructType * SType)340*d415bd75Srobert static bool isSPIRVBuiltinType(const StructType *SType) {
341*d415bd75Srobert   return SType->isOpaque() && SType->hasName() &&
342*d415bd75Srobert          SType->getName().startswith("spirv.");
343*d415bd75Srobert }
344*d415bd75Srobert 
getTypedPtrEltType(const Type * Ty)345*d415bd75Srobert const Type *getTypedPtrEltType(const Type *Ty) {
346*d415bd75Srobert   auto PType = dyn_cast<PointerType>(Ty);
347*d415bd75Srobert   if (!PType || PType->isOpaque())
348*d415bd75Srobert     return Ty;
349*d415bd75Srobert   return PType->getNonOpaquePointerElementType();
350*d415bd75Srobert }
351*d415bd75Srobert 
isSpecialOpaqueType(const Type * Ty)352*d415bd75Srobert bool isSpecialOpaqueType(const Type *Ty) {
353*d415bd75Srobert   if (auto SType = dyn_cast<StructType>(getTypedPtrEltType(Ty)))
354*d415bd75Srobert     return isOpenCLBuiltinType(SType) || isSPIRVBuiltinType(SType);
355*d415bd75Srobert   return false;
356*d415bd75Srobert }
357*d415bd75Srobert } // namespace llvm
358