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. 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. 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 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 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 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 7681ad6265SDimitry Andric std::string getStringImm(const MachineInstr &MI, unsigned StartIndex) { 7781ad6265SDimitry Andric return getSPIRVStringOperand(MI, StartIndex); 7881ad6265SDimitry Andric } 7981ad6265SDimitry Andric 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 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, 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 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 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. 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 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 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 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 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 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 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 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. 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 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 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 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 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 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 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 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 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