xref: /freebsd/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVUtils.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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"
17*0fca6ea1SDimitry Andric #include "SPIRVSubtarget.h"
1881ad6265SDimitry Andric #include "llvm/ADT/StringRef.h"
195f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
2081ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
2181ad6265SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
2281ad6265SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
23bdd1243dSDimitry Andric #include "llvm/Demangle/Demangle.h"
2481ad6265SDimitry Andric #include "llvm/IR/IntrinsicsSPIRV.h"
2581ad6265SDimitry Andric 
26bdd1243dSDimitry Andric namespace llvm {
2781ad6265SDimitry Andric 
2881ad6265SDimitry Andric // The following functions are used to add these string literals as a series of
2981ad6265SDimitry Andric // 32-bit integer operands with the correct format, and unpack them if necessary
3081ad6265SDimitry Andric // when making string comparisons in compiler passes.
3181ad6265SDimitry Andric // SPIR-V requires null-terminated UTF-8 strings padded to 32-bit alignment.
convertCharsToWord(const StringRef & Str,unsigned i)3281ad6265SDimitry Andric static uint32_t convertCharsToWord(const StringRef &Str, unsigned i) {
3381ad6265SDimitry Andric   uint32_t Word = 0u; // Build up this 32-bit word from 4 8-bit chars.
3481ad6265SDimitry Andric   for (unsigned WordIndex = 0; WordIndex < 4; ++WordIndex) {
3581ad6265SDimitry Andric     unsigned StrIndex = i + WordIndex;
3681ad6265SDimitry Andric     uint8_t CharToAdd = 0;       // Initilize char as padding/null.
3781ad6265SDimitry Andric     if (StrIndex < Str.size()) { // If it's within the string, get a real char.
3881ad6265SDimitry Andric       CharToAdd = Str[StrIndex];
3981ad6265SDimitry Andric     }
4081ad6265SDimitry Andric     Word |= (CharToAdd << (WordIndex * 8));
4181ad6265SDimitry Andric   }
4281ad6265SDimitry Andric   return Word;
4381ad6265SDimitry Andric }
4481ad6265SDimitry Andric 
4581ad6265SDimitry Andric // Get length including padding and null terminator.
getPaddedLen(const StringRef & Str)4681ad6265SDimitry Andric static size_t getPaddedLen(const StringRef &Str) {
4781ad6265SDimitry Andric   const size_t Len = Str.size() + 1;
4881ad6265SDimitry Andric   return (Len % 4 == 0) ? Len : Len + (4 - (Len % 4));
4981ad6265SDimitry Andric }
5081ad6265SDimitry Andric 
addStringImm(const StringRef & Str,MCInst & Inst)51fcaf7f86SDimitry Andric void addStringImm(const StringRef &Str, MCInst &Inst) {
52fcaf7f86SDimitry Andric   const size_t PaddedLen = getPaddedLen(Str);
53fcaf7f86SDimitry Andric   for (unsigned i = 0; i < PaddedLen; i += 4) {
54fcaf7f86SDimitry Andric     // Add an operand for the 32-bits of chars or padding.
55fcaf7f86SDimitry Andric     Inst.addOperand(MCOperand::createImm(convertCharsToWord(Str, i)));
56fcaf7f86SDimitry Andric   }
57fcaf7f86SDimitry Andric }
58fcaf7f86SDimitry Andric 
addStringImm(const StringRef & Str,MachineInstrBuilder & MIB)5981ad6265SDimitry Andric void addStringImm(const StringRef &Str, MachineInstrBuilder &MIB) {
6081ad6265SDimitry Andric   const size_t PaddedLen = getPaddedLen(Str);
6181ad6265SDimitry Andric   for (unsigned i = 0; i < PaddedLen; i += 4) {
6281ad6265SDimitry Andric     // Add an operand for the 32-bits of chars or padding.
6381ad6265SDimitry Andric     MIB.addImm(convertCharsToWord(Str, i));
6481ad6265SDimitry Andric   }
6581ad6265SDimitry Andric }
6681ad6265SDimitry Andric 
addStringImm(const StringRef & Str,IRBuilder<> & B,std::vector<Value * > & Args)6781ad6265SDimitry Andric void addStringImm(const StringRef &Str, IRBuilder<> &B,
6881ad6265SDimitry Andric                   std::vector<Value *> &Args) {
6981ad6265SDimitry Andric   const size_t PaddedLen = getPaddedLen(Str);
7081ad6265SDimitry Andric   for (unsigned i = 0; i < PaddedLen; i += 4) {
7181ad6265SDimitry Andric     // Add a vector element for the 32-bits of chars or padding.
7281ad6265SDimitry Andric     Args.push_back(B.getInt32(convertCharsToWord(Str, i)));
7381ad6265SDimitry Andric   }
7481ad6265SDimitry Andric }
7581ad6265SDimitry Andric 
getStringImm(const MachineInstr & MI,unsigned StartIndex)7681ad6265SDimitry Andric std::string getStringImm(const MachineInstr &MI, unsigned StartIndex) {
7781ad6265SDimitry Andric   return getSPIRVStringOperand(MI, StartIndex);
7881ad6265SDimitry Andric }
7981ad6265SDimitry Andric 
addNumImm(const APInt & Imm,MachineInstrBuilder & MIB)8081ad6265SDimitry Andric void addNumImm(const APInt &Imm, MachineInstrBuilder &MIB) {
8181ad6265SDimitry Andric   const auto Bitwidth = Imm.getBitWidth();
8206c3fb27SDimitry Andric   if (Bitwidth == 1)
8306c3fb27SDimitry Andric     return; // Already handled
8406c3fb27SDimitry Andric   else if (Bitwidth <= 32) {
8581ad6265SDimitry Andric     MIB.addImm(Imm.getZExtValue());
86*0fca6ea1SDimitry Andric     // Asm Printer needs this info to print floating-type correctly
87*0fca6ea1SDimitry Andric     if (Bitwidth == 16)
88*0fca6ea1SDimitry Andric       MIB.getInstr()->setAsmPrinterFlag(SPIRV::ASM_PRINTER_WIDTH16);
8906c3fb27SDimitry Andric     return;
9006c3fb27SDimitry Andric   } else if (Bitwidth <= 64) {
9181ad6265SDimitry Andric     uint64_t FullImm = Imm.getZExtValue();
9281ad6265SDimitry Andric     uint32_t LowBits = FullImm & 0xffffffff;
9381ad6265SDimitry Andric     uint32_t HighBits = (FullImm >> 32) & 0xffffffff;
9481ad6265SDimitry Andric     MIB.addImm(LowBits).addImm(HighBits);
9506c3fb27SDimitry Andric     return;
9681ad6265SDimitry Andric   }
9781ad6265SDimitry Andric   report_fatal_error("Unsupported constant bitwidth");
9881ad6265SDimitry Andric }
9981ad6265SDimitry Andric 
buildOpName(Register Target,const StringRef & Name,MachineIRBuilder & MIRBuilder)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 
finishBuildOpDecorate(MachineInstrBuilder & MIB,const std::vector<uint32_t> & DecArgs,StringRef StrImm)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 
buildOpDecorate(Register Reg,MachineIRBuilder & MIRBuilder,SPIRV::Decoration::Decoration Dec,const std::vector<uint32_t> & DecArgs,StringRef StrImm)11781ad6265SDimitry Andric void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder,
118bdd1243dSDimitry 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 
buildOpDecorate(Register Reg,MachineInstr & I,const SPIRVInstrInfo & TII,SPIRV::Decoration::Decoration Dec,const std::vector<uint32_t> & DecArgs,StringRef StrImm)12681ad6265SDimitry Andric void buildOpDecorate(Register Reg, MachineInstr &I, const SPIRVInstrInfo &TII,
127bdd1243dSDimitry 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 
buildOpSpirvDecorations(Register Reg,MachineIRBuilder & MIRBuilder,const MDNode * GVarMD)136*0fca6ea1SDimitry Andric void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
137*0fca6ea1SDimitry Andric                              const MDNode *GVarMD) {
138*0fca6ea1SDimitry Andric   for (unsigned I = 0, E = GVarMD->getNumOperands(); I != E; ++I) {
139*0fca6ea1SDimitry Andric     auto *OpMD = dyn_cast<MDNode>(GVarMD->getOperand(I));
140*0fca6ea1SDimitry Andric     if (!OpMD)
141*0fca6ea1SDimitry Andric       report_fatal_error("Invalid decoration");
142*0fca6ea1SDimitry Andric     if (OpMD->getNumOperands() == 0)
143*0fca6ea1SDimitry Andric       report_fatal_error("Expect operand(s) of the decoration");
144*0fca6ea1SDimitry Andric     ConstantInt *DecorationId =
145*0fca6ea1SDimitry Andric         mdconst::dyn_extract<ConstantInt>(OpMD->getOperand(0));
146*0fca6ea1SDimitry Andric     if (!DecorationId)
147*0fca6ea1SDimitry Andric       report_fatal_error("Expect SPIR-V <Decoration> operand to be the first "
148*0fca6ea1SDimitry Andric                          "element of the decoration");
149*0fca6ea1SDimitry Andric     auto MIB = MIRBuilder.buildInstr(SPIRV::OpDecorate)
150*0fca6ea1SDimitry Andric                    .addUse(Reg)
151*0fca6ea1SDimitry Andric                    .addImm(static_cast<uint32_t>(DecorationId->getZExtValue()));
152*0fca6ea1SDimitry Andric     for (unsigned OpI = 1, OpE = OpMD->getNumOperands(); OpI != OpE; ++OpI) {
153*0fca6ea1SDimitry Andric       if (ConstantInt *OpV =
154*0fca6ea1SDimitry Andric               mdconst::dyn_extract<ConstantInt>(OpMD->getOperand(OpI)))
155*0fca6ea1SDimitry Andric         MIB.addImm(static_cast<uint32_t>(OpV->getZExtValue()));
156*0fca6ea1SDimitry Andric       else if (MDString *OpV = dyn_cast<MDString>(OpMD->getOperand(OpI)))
157*0fca6ea1SDimitry Andric         addStringImm(OpV->getString(), MIB);
158*0fca6ea1SDimitry Andric       else
159*0fca6ea1SDimitry Andric         report_fatal_error("Unexpected operand of the decoration");
160*0fca6ea1SDimitry Andric     }
161*0fca6ea1SDimitry Andric   }
162*0fca6ea1SDimitry Andric }
163*0fca6ea1SDimitry Andric 
16481ad6265SDimitry Andric // TODO: maybe the following two functions should be handled in the subtarget
16581ad6265SDimitry Andric // to allow for different OpenCL vs Vulkan handling.
storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC)166bdd1243dSDimitry Andric unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC) {
16781ad6265SDimitry Andric   switch (SC) {
16881ad6265SDimitry Andric   case SPIRV::StorageClass::Function:
16981ad6265SDimitry Andric     return 0;
17081ad6265SDimitry Andric   case SPIRV::StorageClass::CrossWorkgroup:
17181ad6265SDimitry Andric     return 1;
17281ad6265SDimitry Andric   case SPIRV::StorageClass::UniformConstant:
17381ad6265SDimitry Andric     return 2;
17481ad6265SDimitry Andric   case SPIRV::StorageClass::Workgroup:
17581ad6265SDimitry Andric     return 3;
17681ad6265SDimitry Andric   case SPIRV::StorageClass::Generic:
17781ad6265SDimitry Andric     return 4;
178*0fca6ea1SDimitry Andric   case SPIRV::StorageClass::DeviceOnlyINTEL:
179*0fca6ea1SDimitry Andric     return 5;
180*0fca6ea1SDimitry Andric   case SPIRV::StorageClass::HostOnlyINTEL:
181*0fca6ea1SDimitry Andric     return 6;
18281ad6265SDimitry Andric   case SPIRV::StorageClass::Input:
18381ad6265SDimitry Andric     return 7;
18481ad6265SDimitry Andric   default:
185*0fca6ea1SDimitry Andric     report_fatal_error("Unable to get address space id");
18681ad6265SDimitry Andric   }
18781ad6265SDimitry Andric }
18881ad6265SDimitry Andric 
189bdd1243dSDimitry Andric SPIRV::StorageClass::StorageClass
addressSpaceToStorageClass(unsigned AddrSpace,const SPIRVSubtarget & STI)190*0fca6ea1SDimitry Andric addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI) {
19181ad6265SDimitry Andric   switch (AddrSpace) {
19281ad6265SDimitry Andric   case 0:
19381ad6265SDimitry Andric     return SPIRV::StorageClass::Function;
19481ad6265SDimitry Andric   case 1:
19581ad6265SDimitry Andric     return SPIRV::StorageClass::CrossWorkgroup;
19681ad6265SDimitry Andric   case 2:
19781ad6265SDimitry Andric     return SPIRV::StorageClass::UniformConstant;
19881ad6265SDimitry Andric   case 3:
19981ad6265SDimitry Andric     return SPIRV::StorageClass::Workgroup;
20081ad6265SDimitry Andric   case 4:
20181ad6265SDimitry Andric     return SPIRV::StorageClass::Generic;
202*0fca6ea1SDimitry Andric   case 5:
203*0fca6ea1SDimitry Andric     return STI.canUseExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes)
204*0fca6ea1SDimitry Andric                ? SPIRV::StorageClass::DeviceOnlyINTEL
205*0fca6ea1SDimitry Andric                : SPIRV::StorageClass::CrossWorkgroup;
206*0fca6ea1SDimitry Andric   case 6:
207*0fca6ea1SDimitry Andric     return STI.canUseExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes)
208*0fca6ea1SDimitry Andric                ? SPIRV::StorageClass::HostOnlyINTEL
209*0fca6ea1SDimitry Andric                : SPIRV::StorageClass::CrossWorkgroup;
21081ad6265SDimitry Andric   case 7:
21181ad6265SDimitry Andric     return SPIRV::StorageClass::Input;
21281ad6265SDimitry Andric   default:
213*0fca6ea1SDimitry Andric     report_fatal_error("Unknown address space");
21481ad6265SDimitry Andric   }
21581ad6265SDimitry Andric }
21681ad6265SDimitry Andric 
217bdd1243dSDimitry Andric SPIRV::MemorySemantics::MemorySemantics
getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC)218bdd1243dSDimitry Andric getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC) {
21981ad6265SDimitry Andric   switch (SC) {
22081ad6265SDimitry Andric   case SPIRV::StorageClass::StorageBuffer:
22181ad6265SDimitry Andric   case SPIRV::StorageClass::Uniform:
22281ad6265SDimitry Andric     return SPIRV::MemorySemantics::UniformMemory;
22381ad6265SDimitry Andric   case SPIRV::StorageClass::Workgroup:
22481ad6265SDimitry Andric     return SPIRV::MemorySemantics::WorkgroupMemory;
22581ad6265SDimitry Andric   case SPIRV::StorageClass::CrossWorkgroup:
22681ad6265SDimitry Andric     return SPIRV::MemorySemantics::CrossWorkgroupMemory;
22781ad6265SDimitry Andric   case SPIRV::StorageClass::AtomicCounter:
22881ad6265SDimitry Andric     return SPIRV::MemorySemantics::AtomicCounterMemory;
22981ad6265SDimitry Andric   case SPIRV::StorageClass::Image:
23081ad6265SDimitry Andric     return SPIRV::MemorySemantics::ImageMemory;
23181ad6265SDimitry Andric   default:
23281ad6265SDimitry Andric     return SPIRV::MemorySemantics::None;
23381ad6265SDimitry Andric   }
23481ad6265SDimitry Andric }
23581ad6265SDimitry Andric 
getMemSemantics(AtomicOrdering Ord)236bdd1243dSDimitry Andric SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord) {
237fcaf7f86SDimitry Andric   switch (Ord) {
238fcaf7f86SDimitry Andric   case AtomicOrdering::Acquire:
239fcaf7f86SDimitry Andric     return SPIRV::MemorySemantics::Acquire;
240fcaf7f86SDimitry Andric   case AtomicOrdering::Release:
241fcaf7f86SDimitry Andric     return SPIRV::MemorySemantics::Release;
242fcaf7f86SDimitry Andric   case AtomicOrdering::AcquireRelease:
243fcaf7f86SDimitry Andric     return SPIRV::MemorySemantics::AcquireRelease;
244fcaf7f86SDimitry Andric   case AtomicOrdering::SequentiallyConsistent:
245fcaf7f86SDimitry Andric     return SPIRV::MemorySemantics::SequentiallyConsistent;
246fcaf7f86SDimitry Andric   case AtomicOrdering::Unordered:
247fcaf7f86SDimitry Andric   case AtomicOrdering::Monotonic:
248fcaf7f86SDimitry Andric   case AtomicOrdering::NotAtomic:
249fcaf7f86SDimitry Andric     return SPIRV::MemorySemantics::None;
250fcaf7f86SDimitry Andric   }
25106c3fb27SDimitry Andric   llvm_unreachable(nullptr);
252fcaf7f86SDimitry Andric }
253fcaf7f86SDimitry Andric 
getDefInstrMaybeConstant(Register & ConstReg,const MachineRegisterInfo * MRI)25481ad6265SDimitry Andric MachineInstr *getDefInstrMaybeConstant(Register &ConstReg,
25581ad6265SDimitry Andric                                        const MachineRegisterInfo *MRI) {
256*0fca6ea1SDimitry Andric   MachineInstr *MI = MRI->getVRegDef(ConstReg);
257*0fca6ea1SDimitry Andric   MachineInstr *ConstInstr =
258*0fca6ea1SDimitry Andric       MI->getOpcode() == SPIRV::G_TRUNC || MI->getOpcode() == SPIRV::G_ZEXT
259*0fca6ea1SDimitry Andric           ? MRI->getVRegDef(MI->getOperand(1).getReg())
260*0fca6ea1SDimitry Andric           : MI;
2615f757f3fSDimitry Andric   if (auto *GI = dyn_cast<GIntrinsic>(ConstInstr)) {
2625f757f3fSDimitry Andric     if (GI->is(Intrinsic::spv_track_constant)) {
26381ad6265SDimitry Andric       ConstReg = ConstInstr->getOperand(2).getReg();
2645f757f3fSDimitry Andric       return MRI->getVRegDef(ConstReg);
2655f757f3fSDimitry Andric     }
26681ad6265SDimitry Andric   } else if (ConstInstr->getOpcode() == SPIRV::ASSIGN_TYPE) {
26781ad6265SDimitry Andric     ConstReg = ConstInstr->getOperand(1).getReg();
2685f757f3fSDimitry Andric     return MRI->getVRegDef(ConstReg);
26981ad6265SDimitry Andric   }
2705f757f3fSDimitry Andric   return MRI->getVRegDef(ConstReg);
27181ad6265SDimitry Andric }
27281ad6265SDimitry Andric 
getIConstVal(Register ConstReg,const MachineRegisterInfo * MRI)27381ad6265SDimitry Andric uint64_t getIConstVal(Register ConstReg, const MachineRegisterInfo *MRI) {
27481ad6265SDimitry Andric   const MachineInstr *MI = getDefInstrMaybeConstant(ConstReg, MRI);
27581ad6265SDimitry Andric   assert(MI && MI->getOpcode() == TargetOpcode::G_CONSTANT);
27681ad6265SDimitry Andric   return MI->getOperand(1).getCImm()->getValue().getZExtValue();
27781ad6265SDimitry Andric }
27881ad6265SDimitry Andric 
isSpvIntrinsic(const MachineInstr & MI,Intrinsic::ID IntrinsicID)2791db9f3b2SDimitry Andric bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID) {
2801db9f3b2SDimitry Andric   if (const auto *GI = dyn_cast<GIntrinsic>(&MI))
2815f757f3fSDimitry Andric     return GI->is(IntrinsicID);
2825f757f3fSDimitry Andric   return false;
283fcaf7f86SDimitry Andric }
284fcaf7f86SDimitry Andric 
getMDOperandAsType(const MDNode * N,unsigned I)28581ad6265SDimitry Andric Type *getMDOperandAsType(const MDNode *N, unsigned I) {
286*0fca6ea1SDimitry Andric   Type *ElementTy = cast<ValueAsMetadata>(N->getOperand(I))->getType();
287*0fca6ea1SDimitry Andric   return toTypedPointer(ElementTy);
28881ad6265SDimitry Andric }
289bdd1243dSDimitry Andric 
290bdd1243dSDimitry Andric // The set of names is borrowed from the SPIR-V translator.
291bdd1243dSDimitry Andric // TODO: may be implemented in SPIRVBuiltins.td.
isPipeOrAddressSpaceCastBI(const StringRef MangledName)292bdd1243dSDimitry Andric static bool isPipeOrAddressSpaceCastBI(const StringRef MangledName) {
293bdd1243dSDimitry Andric   return MangledName == "write_pipe_2" || MangledName == "read_pipe_2" ||
294bdd1243dSDimitry Andric          MangledName == "write_pipe_2_bl" || MangledName == "read_pipe_2_bl" ||
295bdd1243dSDimitry Andric          MangledName == "write_pipe_4" || MangledName == "read_pipe_4" ||
296bdd1243dSDimitry Andric          MangledName == "reserve_write_pipe" ||
297bdd1243dSDimitry Andric          MangledName == "reserve_read_pipe" ||
298bdd1243dSDimitry Andric          MangledName == "commit_write_pipe" ||
299bdd1243dSDimitry Andric          MangledName == "commit_read_pipe" ||
300bdd1243dSDimitry Andric          MangledName == "work_group_reserve_write_pipe" ||
301bdd1243dSDimitry Andric          MangledName == "work_group_reserve_read_pipe" ||
302bdd1243dSDimitry Andric          MangledName == "work_group_commit_write_pipe" ||
303bdd1243dSDimitry Andric          MangledName == "work_group_commit_read_pipe" ||
304bdd1243dSDimitry Andric          MangledName == "get_pipe_num_packets_ro" ||
305bdd1243dSDimitry Andric          MangledName == "get_pipe_max_packets_ro" ||
306bdd1243dSDimitry Andric          MangledName == "get_pipe_num_packets_wo" ||
307bdd1243dSDimitry Andric          MangledName == "get_pipe_max_packets_wo" ||
308bdd1243dSDimitry Andric          MangledName == "sub_group_reserve_write_pipe" ||
309bdd1243dSDimitry Andric          MangledName == "sub_group_reserve_read_pipe" ||
310bdd1243dSDimitry Andric          MangledName == "sub_group_commit_write_pipe" ||
311bdd1243dSDimitry Andric          MangledName == "sub_group_commit_read_pipe" ||
312bdd1243dSDimitry Andric          MangledName == "to_global" || MangledName == "to_local" ||
313bdd1243dSDimitry Andric          MangledName == "to_private";
314bdd1243dSDimitry Andric }
315bdd1243dSDimitry Andric 
isEnqueueKernelBI(const StringRef MangledName)316bdd1243dSDimitry Andric static bool isEnqueueKernelBI(const StringRef MangledName) {
317bdd1243dSDimitry Andric   return MangledName == "__enqueue_kernel_basic" ||
318bdd1243dSDimitry Andric          MangledName == "__enqueue_kernel_basic_events" ||
319bdd1243dSDimitry Andric          MangledName == "__enqueue_kernel_varargs" ||
320bdd1243dSDimitry Andric          MangledName == "__enqueue_kernel_events_varargs";
321bdd1243dSDimitry Andric }
322bdd1243dSDimitry Andric 
isKernelQueryBI(const StringRef MangledName)323bdd1243dSDimitry Andric static bool isKernelQueryBI(const StringRef MangledName) {
324bdd1243dSDimitry Andric   return MangledName == "__get_kernel_work_group_size_impl" ||
325bdd1243dSDimitry Andric          MangledName == "__get_kernel_sub_group_count_for_ndrange_impl" ||
326bdd1243dSDimitry Andric          MangledName == "__get_kernel_max_sub_group_size_for_ndrange_impl" ||
327bdd1243dSDimitry Andric          MangledName == "__get_kernel_preferred_work_group_size_multiple_impl";
328bdd1243dSDimitry Andric }
329bdd1243dSDimitry Andric 
isNonMangledOCLBuiltin(StringRef Name)330bdd1243dSDimitry Andric static bool isNonMangledOCLBuiltin(StringRef Name) {
3315f757f3fSDimitry Andric   if (!Name.starts_with("__"))
332bdd1243dSDimitry Andric     return false;
333bdd1243dSDimitry Andric 
334bdd1243dSDimitry Andric   return isEnqueueKernelBI(Name) || isKernelQueryBI(Name) ||
335bdd1243dSDimitry Andric          isPipeOrAddressSpaceCastBI(Name.drop_front(2)) ||
336bdd1243dSDimitry Andric          Name == "__translate_sampler_initializer";
337bdd1243dSDimitry Andric }
338bdd1243dSDimitry Andric 
getOclOrSpirvBuiltinDemangledName(StringRef Name)339bdd1243dSDimitry Andric std::string getOclOrSpirvBuiltinDemangledName(StringRef Name) {
340bdd1243dSDimitry Andric   bool IsNonMangledOCL = isNonMangledOCLBuiltin(Name);
3415f757f3fSDimitry Andric   bool IsNonMangledSPIRV = Name.starts_with("__spirv_");
342*0fca6ea1SDimitry Andric   bool IsNonMangledHLSL = Name.starts_with("__hlsl_");
3435f757f3fSDimitry Andric   bool IsMangled = Name.starts_with("_Z");
344bdd1243dSDimitry Andric 
345*0fca6ea1SDimitry Andric   // Otherwise use simple demangling to return the function name.
346*0fca6ea1SDimitry Andric   if (IsNonMangledOCL || IsNonMangledSPIRV || IsNonMangledHLSL || !IsMangled)
347*0fca6ea1SDimitry Andric     return Name.str();
348bdd1243dSDimitry Andric 
349bdd1243dSDimitry Andric   // Try to use the itanium demangler.
35006c3fb27SDimitry Andric   if (char *DemangledName = itaniumDemangle(Name.data())) {
351bdd1243dSDimitry Andric     std::string Result = DemangledName;
352bdd1243dSDimitry Andric     free(DemangledName);
353bdd1243dSDimitry Andric     return Result;
354bdd1243dSDimitry Andric   }
355bdd1243dSDimitry Andric 
356bdd1243dSDimitry Andric   // Autocheck C++, maybe need to do explicit check of the source language.
357bdd1243dSDimitry Andric   // OpenCL C++ built-ins are declared in cl namespace.
358bdd1243dSDimitry Andric   // TODO: consider using 'St' abbriviation for cl namespace mangling.
359bdd1243dSDimitry Andric   // Similar to ::std:: in C++.
360bdd1243dSDimitry Andric   size_t Start, Len = 0;
361bdd1243dSDimitry Andric   size_t DemangledNameLenStart = 2;
3625f757f3fSDimitry Andric   if (Name.starts_with("_ZN")) {
363bdd1243dSDimitry Andric     // Skip CV and ref qualifiers.
364bdd1243dSDimitry Andric     size_t NameSpaceStart = Name.find_first_not_of("rVKRO", 3);
365bdd1243dSDimitry Andric     // All built-ins are in the ::cl:: namespace.
366bdd1243dSDimitry Andric     if (Name.substr(NameSpaceStart, 11) != "2cl7__spirv")
367bdd1243dSDimitry Andric       return std::string();
368bdd1243dSDimitry Andric     DemangledNameLenStart = NameSpaceStart + 11;
369bdd1243dSDimitry Andric   }
370bdd1243dSDimitry Andric   Start = Name.find_first_not_of("0123456789", DemangledNameLenStart);
371bdd1243dSDimitry Andric   Name.substr(DemangledNameLenStart, Start - DemangledNameLenStart)
372bdd1243dSDimitry Andric       .getAsInteger(10, Len);
373bdd1243dSDimitry Andric   return Name.substr(Start, Len).str();
374bdd1243dSDimitry Andric }
375bdd1243dSDimitry Andric 
hasBuiltinTypePrefix(StringRef Name)3765f757f3fSDimitry Andric bool hasBuiltinTypePrefix(StringRef Name) {
377*0fca6ea1SDimitry Andric   if (Name.starts_with("opencl.") || Name.starts_with("ocl_") ||
378*0fca6ea1SDimitry Andric       Name.starts_with("spirv."))
37906c3fb27SDimitry Andric     return true;
38006c3fb27SDimitry Andric   return false;
38106c3fb27SDimitry Andric }
38206c3fb27SDimitry Andric 
isSpecialOpaqueType(const Type * Ty)383bdd1243dSDimitry Andric bool isSpecialOpaqueType(const Type *Ty) {
384*0fca6ea1SDimitry Andric   if (const TargetExtType *EType = dyn_cast<TargetExtType>(Ty))
38506c3fb27SDimitry Andric     return hasBuiltinTypePrefix(EType->getName());
38606c3fb27SDimitry Andric 
387bdd1243dSDimitry Andric   return false;
388bdd1243dSDimitry Andric }
389*0fca6ea1SDimitry Andric 
isEntryPoint(const Function & F)390*0fca6ea1SDimitry Andric bool isEntryPoint(const Function &F) {
391*0fca6ea1SDimitry Andric   // OpenCL handling: any function with the SPIR_KERNEL
392*0fca6ea1SDimitry Andric   // calling convention will be a potential entry point.
393*0fca6ea1SDimitry Andric   if (F.getCallingConv() == CallingConv::SPIR_KERNEL)
394*0fca6ea1SDimitry Andric     return true;
395*0fca6ea1SDimitry Andric 
396*0fca6ea1SDimitry Andric   // HLSL handling: special attribute are emitted from the
397*0fca6ea1SDimitry Andric   // front-end.
398*0fca6ea1SDimitry Andric   if (F.getFnAttribute("hlsl.shader").isValid())
399*0fca6ea1SDimitry Andric     return true;
400*0fca6ea1SDimitry Andric 
401*0fca6ea1SDimitry Andric   return false;
402*0fca6ea1SDimitry Andric }
403*0fca6ea1SDimitry Andric 
parseBasicTypeName(StringRef & TypeName,LLVMContext & Ctx)404*0fca6ea1SDimitry Andric Type *parseBasicTypeName(StringRef &TypeName, LLVMContext &Ctx) {
405*0fca6ea1SDimitry Andric   TypeName.consume_front("atomic_");
406*0fca6ea1SDimitry Andric   if (TypeName.consume_front("void"))
407*0fca6ea1SDimitry Andric     return Type::getVoidTy(Ctx);
408*0fca6ea1SDimitry Andric   else if (TypeName.consume_front("bool"))
409*0fca6ea1SDimitry Andric     return Type::getIntNTy(Ctx, 1);
410*0fca6ea1SDimitry Andric   else if (TypeName.consume_front("char") ||
411*0fca6ea1SDimitry Andric            TypeName.consume_front("unsigned char") ||
412*0fca6ea1SDimitry Andric            TypeName.consume_front("uchar"))
413*0fca6ea1SDimitry Andric     return Type::getInt8Ty(Ctx);
414*0fca6ea1SDimitry Andric   else if (TypeName.consume_front("short") ||
415*0fca6ea1SDimitry Andric            TypeName.consume_front("unsigned short") ||
416*0fca6ea1SDimitry Andric            TypeName.consume_front("ushort"))
417*0fca6ea1SDimitry Andric     return Type::getInt16Ty(Ctx);
418*0fca6ea1SDimitry Andric   else if (TypeName.consume_front("int") ||
419*0fca6ea1SDimitry Andric            TypeName.consume_front("unsigned int") ||
420*0fca6ea1SDimitry Andric            TypeName.consume_front("uint"))
421*0fca6ea1SDimitry Andric     return Type::getInt32Ty(Ctx);
422*0fca6ea1SDimitry Andric   else if (TypeName.consume_front("long") ||
423*0fca6ea1SDimitry Andric            TypeName.consume_front("unsigned long") ||
424*0fca6ea1SDimitry Andric            TypeName.consume_front("ulong"))
425*0fca6ea1SDimitry Andric     return Type::getInt64Ty(Ctx);
426*0fca6ea1SDimitry Andric   else if (TypeName.consume_front("half"))
427*0fca6ea1SDimitry Andric     return Type::getHalfTy(Ctx);
428*0fca6ea1SDimitry Andric   else if (TypeName.consume_front("float"))
429*0fca6ea1SDimitry Andric     return Type::getFloatTy(Ctx);
430*0fca6ea1SDimitry Andric   else if (TypeName.consume_front("double"))
431*0fca6ea1SDimitry Andric     return Type::getDoubleTy(Ctx);
432*0fca6ea1SDimitry Andric 
433*0fca6ea1SDimitry Andric   // Unable to recognize SPIRV type name
434*0fca6ea1SDimitry Andric   return nullptr;
435*0fca6ea1SDimitry Andric }
436*0fca6ea1SDimitry Andric 
437bdd1243dSDimitry Andric } // namespace llvm
438