xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVUtils.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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