1eab7d363SIlia Diachkov //===--- SPIRVUtils.cpp ---- SPIR-V Utility Functions -----------*- C++ -*-===// 2eab7d363SIlia Diachkov // 3eab7d363SIlia Diachkov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4eab7d363SIlia Diachkov // See https://llvm.org/LICENSE.txt for license information. 5eab7d363SIlia Diachkov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6eab7d363SIlia Diachkov // 7eab7d363SIlia Diachkov //===----------------------------------------------------------------------===// 8eab7d363SIlia Diachkov // 9eab7d363SIlia Diachkov // This file contains miscellaneous utility functions. 10eab7d363SIlia Diachkov // 11eab7d363SIlia Diachkov //===----------------------------------------------------------------------===// 12eab7d363SIlia Diachkov 13eab7d363SIlia Diachkov #include "SPIRVUtils.h" 14eab7d363SIlia Diachkov #include "MCTargetDesc/SPIRVBaseInfo.h" 15eab7d363SIlia Diachkov #include "SPIRV.h" 16b5132b7dSVyacheslav Levytskyy #include "SPIRVGlobalRegistry.h" 17eab7d363SIlia Diachkov #include "SPIRVInstrInfo.h" 184a602d92SVyacheslav Levytskyy #include "SPIRVSubtarget.h" 19eab7d363SIlia Diachkov #include "llvm/ADT/StringRef.h" 207c760b22SSameer Sahasrabuddhe #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h" 21eab7d363SIlia Diachkov #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 22eab7d363SIlia Diachkov #include "llvm/CodeGen/MachineInstr.h" 23eab7d363SIlia Diachkov #include "llvm/CodeGen/MachineInstrBuilder.h" 24f61eb416SIlia Diachkov #include "llvm/Demangle/Demangle.h" 25b5132b7dSVyacheslav Levytskyy #include "llvm/IR/IntrinsicInst.h" 260098f2aeSIlia Diachkov #include "llvm/IR/IntrinsicsSPIRV.h" 271ed65febSNathan Gauër #include <queue> 281ed65febSNathan Gauër #include <vector> 29eab7d363SIlia Diachkov 30b25b507cSIlia Diachkov namespace llvm { 31eab7d363SIlia Diachkov 32eab7d363SIlia Diachkov // The following functions are used to add these string literals as a series of 33eab7d363SIlia Diachkov // 32-bit integer operands with the correct format, and unpack them if necessary 34eab7d363SIlia Diachkov // when making string comparisons in compiler passes. 35eab7d363SIlia Diachkov // SPIR-V requires null-terminated UTF-8 strings padded to 32-bit alignment. 36eab7d363SIlia Diachkov static uint32_t convertCharsToWord(const StringRef &Str, unsigned i) { 37eab7d363SIlia Diachkov uint32_t Word = 0u; // Build up this 32-bit word from 4 8-bit chars. 38eab7d363SIlia Diachkov for (unsigned WordIndex = 0; WordIndex < 4; ++WordIndex) { 39eab7d363SIlia Diachkov unsigned StrIndex = i + WordIndex; 40eab7d363SIlia Diachkov uint8_t CharToAdd = 0; // Initilize char as padding/null. 41eab7d363SIlia Diachkov if (StrIndex < Str.size()) { // If it's within the string, get a real char. 42eab7d363SIlia Diachkov CharToAdd = Str[StrIndex]; 43eab7d363SIlia Diachkov } 44eab7d363SIlia Diachkov Word |= (CharToAdd << (WordIndex * 8)); 45eab7d363SIlia Diachkov } 46eab7d363SIlia Diachkov return Word; 47eab7d363SIlia Diachkov } 48eab7d363SIlia Diachkov 49eab7d363SIlia Diachkov // Get length including padding and null terminator. 503e79c7feSVyacheslav Levytskyy static size_t getPaddedLen(const StringRef &Str) { 513e79c7feSVyacheslav Levytskyy return (Str.size() + 4) & ~3; 523e79c7feSVyacheslav Levytskyy } 53eab7d363SIlia Diachkov 54b8e1544bSIlia Diachkov void addStringImm(const StringRef &Str, MCInst &Inst) { 55b8e1544bSIlia Diachkov const size_t PaddedLen = getPaddedLen(Str); 56b8e1544bSIlia Diachkov for (unsigned i = 0; i < PaddedLen; i += 4) { 57b8e1544bSIlia Diachkov // Add an operand for the 32-bits of chars or padding. 58b8e1544bSIlia Diachkov Inst.addOperand(MCOperand::createImm(convertCharsToWord(Str, i))); 59b8e1544bSIlia Diachkov } 60b8e1544bSIlia Diachkov } 61b8e1544bSIlia Diachkov 62eab7d363SIlia Diachkov void addStringImm(const StringRef &Str, MachineInstrBuilder &MIB) { 63eab7d363SIlia Diachkov const size_t PaddedLen = getPaddedLen(Str); 64eab7d363SIlia Diachkov for (unsigned i = 0; i < PaddedLen; i += 4) { 65eab7d363SIlia Diachkov // Add an operand for the 32-bits of chars or padding. 66eab7d363SIlia Diachkov MIB.addImm(convertCharsToWord(Str, i)); 67eab7d363SIlia Diachkov } 68eab7d363SIlia Diachkov } 69eab7d363SIlia Diachkov 70eab7d363SIlia Diachkov void addStringImm(const StringRef &Str, IRBuilder<> &B, 71eab7d363SIlia Diachkov std::vector<Value *> &Args) { 72eab7d363SIlia Diachkov const size_t PaddedLen = getPaddedLen(Str); 73eab7d363SIlia Diachkov for (unsigned i = 0; i < PaddedLen; i += 4) { 74eab7d363SIlia Diachkov // Add a vector element for the 32-bits of chars or padding. 75eab7d363SIlia Diachkov Args.push_back(B.getInt32(convertCharsToWord(Str, i))); 76eab7d363SIlia Diachkov } 77eab7d363SIlia Diachkov } 78eab7d363SIlia Diachkov 79eab7d363SIlia Diachkov std::string getStringImm(const MachineInstr &MI, unsigned StartIndex) { 80eab7d363SIlia Diachkov return getSPIRVStringOperand(MI, StartIndex); 81eab7d363SIlia Diachkov } 82eab7d363SIlia Diachkov 83eab7d363SIlia Diachkov void addNumImm(const APInt &Imm, MachineInstrBuilder &MIB) { 84eab7d363SIlia Diachkov const auto Bitwidth = Imm.getBitWidth(); 85dc4330a9SMichal Paszkowski if (Bitwidth == 1) 86dc4330a9SMichal Paszkowski return; // Already handled 87dc4330a9SMichal Paszkowski else if (Bitwidth <= 32) { 88eab7d363SIlia Diachkov MIB.addImm(Imm.getZExtValue()); 89925768eeSVyacheslav Levytskyy // Asm Printer needs this info to print floating-type correctly 90925768eeSVyacheslav Levytskyy if (Bitwidth == 16) 91925768eeSVyacheslav Levytskyy MIB.getInstr()->setAsmPrinterFlag(SPIRV::ASM_PRINTER_WIDTH16); 92dc4330a9SMichal Paszkowski return; 93dc4330a9SMichal Paszkowski } else if (Bitwidth <= 64) { 94eab7d363SIlia Diachkov uint64_t FullImm = Imm.getZExtValue(); 95eab7d363SIlia Diachkov uint32_t LowBits = FullImm & 0xffffffff; 96eab7d363SIlia Diachkov uint32_t HighBits = (FullImm >> 32) & 0xffffffff; 97eab7d363SIlia Diachkov MIB.addImm(LowBits).addImm(HighBits); 98dc4330a9SMichal Paszkowski return; 99eab7d363SIlia Diachkov } 100eab7d363SIlia Diachkov report_fatal_error("Unsupported constant bitwidth"); 101eab7d363SIlia Diachkov } 102eab7d363SIlia Diachkov 103eab7d363SIlia Diachkov void buildOpName(Register Target, const StringRef &Name, 104eab7d363SIlia Diachkov MachineIRBuilder &MIRBuilder) { 105eab7d363SIlia Diachkov if (!Name.empty()) { 106eab7d363SIlia Diachkov auto MIB = MIRBuilder.buildInstr(SPIRV::OpName).addUse(Target); 107eab7d363SIlia Diachkov addStringImm(Name, MIB); 108eab7d363SIlia Diachkov } 109eab7d363SIlia Diachkov } 110eab7d363SIlia Diachkov 111874b4fb6SVyacheslav Levytskyy void buildOpName(Register Target, const StringRef &Name, MachineInstr &I, 112874b4fb6SVyacheslav Levytskyy const SPIRVInstrInfo &TII) { 113874b4fb6SVyacheslav Levytskyy if (!Name.empty()) { 114874b4fb6SVyacheslav Levytskyy auto MIB = 115874b4fb6SVyacheslav Levytskyy BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpName)) 116874b4fb6SVyacheslav Levytskyy .addUse(Target); 117874b4fb6SVyacheslav Levytskyy addStringImm(Name, MIB); 118874b4fb6SVyacheslav Levytskyy } 119874b4fb6SVyacheslav Levytskyy } 120874b4fb6SVyacheslav Levytskyy 121eab7d363SIlia Diachkov static void finishBuildOpDecorate(MachineInstrBuilder &MIB, 122eab7d363SIlia Diachkov const std::vector<uint32_t> &DecArgs, 123eab7d363SIlia Diachkov StringRef StrImm) { 124eab7d363SIlia Diachkov if (!StrImm.empty()) 125eab7d363SIlia Diachkov addStringImm(StrImm, MIB); 126eab7d363SIlia Diachkov for (const auto &DecArg : DecArgs) 127eab7d363SIlia Diachkov MIB.addImm(DecArg); 128eab7d363SIlia Diachkov } 129eab7d363SIlia Diachkov 130eab7d363SIlia Diachkov void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, 131b25b507cSIlia Diachkov SPIRV::Decoration::Decoration Dec, 132eab7d363SIlia Diachkov const std::vector<uint32_t> &DecArgs, StringRef StrImm) { 133eab7d363SIlia Diachkov auto MIB = MIRBuilder.buildInstr(SPIRV::OpDecorate) 134eab7d363SIlia Diachkov .addUse(Reg) 135eab7d363SIlia Diachkov .addImm(static_cast<uint32_t>(Dec)); 136eab7d363SIlia Diachkov finishBuildOpDecorate(MIB, DecArgs, StrImm); 137eab7d363SIlia Diachkov } 138eab7d363SIlia Diachkov 139eab7d363SIlia Diachkov void buildOpDecorate(Register Reg, MachineInstr &I, const SPIRVInstrInfo &TII, 140b25b507cSIlia Diachkov SPIRV::Decoration::Decoration Dec, 141eab7d363SIlia Diachkov const std::vector<uint32_t> &DecArgs, StringRef StrImm) { 142eab7d363SIlia Diachkov MachineBasicBlock &MBB = *I.getParent(); 143eab7d363SIlia Diachkov auto MIB = BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpDecorate)) 144eab7d363SIlia Diachkov .addUse(Reg) 145eab7d363SIlia Diachkov .addImm(static_cast<uint32_t>(Dec)); 146eab7d363SIlia Diachkov finishBuildOpDecorate(MIB, DecArgs, StrImm); 147eab7d363SIlia Diachkov } 148eab7d363SIlia Diachkov 149be9b4dabSVyacheslav Levytskyy void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder, 150be9b4dabSVyacheslav Levytskyy const MDNode *GVarMD) { 151be9b4dabSVyacheslav Levytskyy for (unsigned I = 0, E = GVarMD->getNumOperands(); I != E; ++I) { 152be9b4dabSVyacheslav Levytskyy auto *OpMD = dyn_cast<MDNode>(GVarMD->getOperand(I)); 153be9b4dabSVyacheslav Levytskyy if (!OpMD) 154be9b4dabSVyacheslav Levytskyy report_fatal_error("Invalid decoration"); 155be9b4dabSVyacheslav Levytskyy if (OpMD->getNumOperands() == 0) 156be9b4dabSVyacheslav Levytskyy report_fatal_error("Expect operand(s) of the decoration"); 157be9b4dabSVyacheslav Levytskyy ConstantInt *DecorationId = 158be9b4dabSVyacheslav Levytskyy mdconst::dyn_extract<ConstantInt>(OpMD->getOperand(0)); 159be9b4dabSVyacheslav Levytskyy if (!DecorationId) 160be9b4dabSVyacheslav Levytskyy report_fatal_error("Expect SPIR-V <Decoration> operand to be the first " 161be9b4dabSVyacheslav Levytskyy "element of the decoration"); 162be9b4dabSVyacheslav Levytskyy auto MIB = MIRBuilder.buildInstr(SPIRV::OpDecorate) 163be9b4dabSVyacheslav Levytskyy .addUse(Reg) 164be9b4dabSVyacheslav Levytskyy .addImm(static_cast<uint32_t>(DecorationId->getZExtValue())); 165be9b4dabSVyacheslav Levytskyy for (unsigned OpI = 1, OpE = OpMD->getNumOperands(); OpI != OpE; ++OpI) { 166be9b4dabSVyacheslav Levytskyy if (ConstantInt *OpV = 167be9b4dabSVyacheslav Levytskyy mdconst::dyn_extract<ConstantInt>(OpMD->getOperand(OpI))) 168be9b4dabSVyacheslav Levytskyy MIB.addImm(static_cast<uint32_t>(OpV->getZExtValue())); 169be9b4dabSVyacheslav Levytskyy else if (MDString *OpV = dyn_cast<MDString>(OpMD->getOperand(OpI))) 170be9b4dabSVyacheslav Levytskyy addStringImm(OpV->getString(), MIB); 171be9b4dabSVyacheslav Levytskyy else 172be9b4dabSVyacheslav Levytskyy report_fatal_error("Unexpected operand of the decoration"); 173be9b4dabSVyacheslav Levytskyy } 174be9b4dabSVyacheslav Levytskyy } 175be9b4dabSVyacheslav Levytskyy } 176be9b4dabSVyacheslav Levytskyy 1778ac46d6bSVyacheslav Levytskyy MachineBasicBlock::iterator getOpVariableMBBIt(MachineInstr &I) { 1788ac46d6bSVyacheslav Levytskyy MachineFunction *MF = I.getParent()->getParent(); 1798ac46d6bSVyacheslav Levytskyy MachineBasicBlock *MBB = &MF->front(); 1808ac46d6bSVyacheslav Levytskyy MachineBasicBlock::iterator It = MBB->SkipPHIsAndLabels(MBB->begin()), 1818ac46d6bSVyacheslav Levytskyy E = MBB->end(); 1828ac46d6bSVyacheslav Levytskyy bool IsHeader = false; 1838ac46d6bSVyacheslav Levytskyy unsigned Opcode; 1848ac46d6bSVyacheslav Levytskyy for (; It != E && It != I; ++It) { 1858ac46d6bSVyacheslav Levytskyy Opcode = It->getOpcode(); 1868ac46d6bSVyacheslav Levytskyy if (Opcode == SPIRV::OpFunction || Opcode == SPIRV::OpFunctionParameter) { 1878ac46d6bSVyacheslav Levytskyy IsHeader = true; 1888ac46d6bSVyacheslav Levytskyy } else if (IsHeader && 1898ac46d6bSVyacheslav Levytskyy !(Opcode == SPIRV::ASSIGN_TYPE || Opcode == SPIRV::OpLabel)) { 1908ac46d6bSVyacheslav Levytskyy ++It; 1918ac46d6bSVyacheslav Levytskyy break; 1928ac46d6bSVyacheslav Levytskyy } 1938ac46d6bSVyacheslav Levytskyy } 1948ac46d6bSVyacheslav Levytskyy return It; 1958ac46d6bSVyacheslav Levytskyy } 1968ac46d6bSVyacheslav Levytskyy 197*3ed2a813SVyacheslav Levytskyy MachineBasicBlock::iterator getInsertPtValidEnd(MachineBasicBlock *MBB) { 198*3ed2a813SVyacheslav Levytskyy MachineBasicBlock::iterator I = MBB->end(); 199*3ed2a813SVyacheslav Levytskyy if (I == MBB->begin()) 200*3ed2a813SVyacheslav Levytskyy return I; 201*3ed2a813SVyacheslav Levytskyy --I; 202*3ed2a813SVyacheslav Levytskyy while (I->isTerminator() || I->isDebugValue()) { 203*3ed2a813SVyacheslav Levytskyy if (I == MBB->begin()) 204*3ed2a813SVyacheslav Levytskyy break; 205*3ed2a813SVyacheslav Levytskyy --I; 206*3ed2a813SVyacheslav Levytskyy } 207*3ed2a813SVyacheslav Levytskyy return I; 208*3ed2a813SVyacheslav Levytskyy } 209*3ed2a813SVyacheslav Levytskyy 210b25b507cSIlia Diachkov SPIRV::StorageClass::StorageClass 2114a602d92SVyacheslav Levytskyy addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI) { 212eab7d363SIlia Diachkov switch (AddrSpace) { 213eab7d363SIlia Diachkov case 0: 214eab7d363SIlia Diachkov return SPIRV::StorageClass::Function; 215eab7d363SIlia Diachkov case 1: 216eab7d363SIlia Diachkov return SPIRV::StorageClass::CrossWorkgroup; 217eab7d363SIlia Diachkov case 2: 218eab7d363SIlia Diachkov return SPIRV::StorageClass::UniformConstant; 219eab7d363SIlia Diachkov case 3: 220eab7d363SIlia Diachkov return SPIRV::StorageClass::Workgroup; 221eab7d363SIlia Diachkov case 4: 222eab7d363SIlia Diachkov return SPIRV::StorageClass::Generic; 2234a602d92SVyacheslav Levytskyy case 5: 2244a602d92SVyacheslav Levytskyy return STI.canUseExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes) 2254a602d92SVyacheslav Levytskyy ? SPIRV::StorageClass::DeviceOnlyINTEL 2264a602d92SVyacheslav Levytskyy : SPIRV::StorageClass::CrossWorkgroup; 2274a602d92SVyacheslav Levytskyy case 6: 2284a602d92SVyacheslav Levytskyy return STI.canUseExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes) 2294a602d92SVyacheslav Levytskyy ? SPIRV::StorageClass::HostOnlyINTEL 2304a602d92SVyacheslav Levytskyy : SPIRV::StorageClass::CrossWorkgroup; 231eab7d363SIlia Diachkov case 7: 232eab7d363SIlia Diachkov return SPIRV::StorageClass::Input; 2335f99eb9bSNathan Gauër case 8: 2345f99eb9bSNathan Gauër return SPIRV::StorageClass::Output; 23586b69c31SVyacheslav Levytskyy case 9: 23686b69c31SVyacheslav Levytskyy return SPIRV::StorageClass::CodeSectionINTEL; 2375f99eb9bSNathan Gauër case 10: 2385f99eb9bSNathan Gauër return SPIRV::StorageClass::Private; 239eab7d363SIlia Diachkov default: 2404a602d92SVyacheslav Levytskyy report_fatal_error("Unknown address space"); 241eab7d363SIlia Diachkov } 242eab7d363SIlia Diachkov } 243eab7d363SIlia Diachkov 244b25b507cSIlia Diachkov SPIRV::MemorySemantics::MemorySemantics 245b25b507cSIlia Diachkov getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC) { 246eab7d363SIlia Diachkov switch (SC) { 247eab7d363SIlia Diachkov case SPIRV::StorageClass::StorageBuffer: 248eab7d363SIlia Diachkov case SPIRV::StorageClass::Uniform: 249eab7d363SIlia Diachkov return SPIRV::MemorySemantics::UniformMemory; 250eab7d363SIlia Diachkov case SPIRV::StorageClass::Workgroup: 251eab7d363SIlia Diachkov return SPIRV::MemorySemantics::WorkgroupMemory; 252eab7d363SIlia Diachkov case SPIRV::StorageClass::CrossWorkgroup: 253eab7d363SIlia Diachkov return SPIRV::MemorySemantics::CrossWorkgroupMemory; 254eab7d363SIlia Diachkov case SPIRV::StorageClass::AtomicCounter: 255eab7d363SIlia Diachkov return SPIRV::MemorySemantics::AtomicCounterMemory; 256eab7d363SIlia Diachkov case SPIRV::StorageClass::Image: 257eab7d363SIlia Diachkov return SPIRV::MemorySemantics::ImageMemory; 258eab7d363SIlia Diachkov default: 259eab7d363SIlia Diachkov return SPIRV::MemorySemantics::None; 260eab7d363SIlia Diachkov } 261eab7d363SIlia Diachkov } 2620098f2aeSIlia Diachkov 263b25b507cSIlia Diachkov SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord) { 264b8e1544bSIlia Diachkov switch (Ord) { 265b8e1544bSIlia Diachkov case AtomicOrdering::Acquire: 266b8e1544bSIlia Diachkov return SPIRV::MemorySemantics::Acquire; 267b8e1544bSIlia Diachkov case AtomicOrdering::Release: 268b8e1544bSIlia Diachkov return SPIRV::MemorySemantics::Release; 269b8e1544bSIlia Diachkov case AtomicOrdering::AcquireRelease: 270b8e1544bSIlia Diachkov return SPIRV::MemorySemantics::AcquireRelease; 271b8e1544bSIlia Diachkov case AtomicOrdering::SequentiallyConsistent: 272b8e1544bSIlia Diachkov return SPIRV::MemorySemantics::SequentiallyConsistent; 273b8e1544bSIlia Diachkov case AtomicOrdering::Unordered: 274b8e1544bSIlia Diachkov case AtomicOrdering::Monotonic: 275b8e1544bSIlia Diachkov case AtomicOrdering::NotAtomic: 276b8e1544bSIlia Diachkov return SPIRV::MemorySemantics::None; 277b8e1544bSIlia Diachkov } 278d7259bb7SIlia Diachkov llvm_unreachable(nullptr); 279b8e1544bSIlia Diachkov } 280b8e1544bSIlia Diachkov 2813cfd0c0dSAlex Voicu SPIRV::Scope::Scope getMemScope(LLVMContext &Ctx, SyncScope::ID Id) { 2823cfd0c0dSAlex Voicu // Named by 2833cfd0c0dSAlex Voicu // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#_scope_id. 2843cfd0c0dSAlex Voicu // We don't need aliases for Invocation and CrossDevice, as we already have 2853cfd0c0dSAlex Voicu // them covered by "singlethread" and "" strings respectively (see 2863cfd0c0dSAlex Voicu // implementation of LLVMContext::LLVMContext()). 287bbb3679aSVyacheslav Levytskyy static const llvm::SyncScope::ID SubGroup = 288bbb3679aSVyacheslav Levytskyy Ctx.getOrInsertSyncScopeID("subgroup"); 289bbb3679aSVyacheslav Levytskyy static const llvm::SyncScope::ID WorkGroup = 290bbb3679aSVyacheslav Levytskyy Ctx.getOrInsertSyncScopeID("workgroup"); 291bbb3679aSVyacheslav Levytskyy static const llvm::SyncScope::ID Device = 292bbb3679aSVyacheslav Levytskyy Ctx.getOrInsertSyncScopeID("device"); 2933cfd0c0dSAlex Voicu 2943cfd0c0dSAlex Voicu if (Id == llvm::SyncScope::SingleThread) 2953cfd0c0dSAlex Voicu return SPIRV::Scope::Invocation; 2963cfd0c0dSAlex Voicu else if (Id == llvm::SyncScope::System) 2973cfd0c0dSAlex Voicu return SPIRV::Scope::CrossDevice; 298bbb3679aSVyacheslav Levytskyy else if (Id == SubGroup) 2993cfd0c0dSAlex Voicu return SPIRV::Scope::Subgroup; 300bbb3679aSVyacheslav Levytskyy else if (Id == WorkGroup) 3013cfd0c0dSAlex Voicu return SPIRV::Scope::Workgroup; 302bbb3679aSVyacheslav Levytskyy else if (Id == Device) 3033cfd0c0dSAlex Voicu return SPIRV::Scope::Device; 3043cfd0c0dSAlex Voicu return SPIRV::Scope::CrossDevice; 3053cfd0c0dSAlex Voicu } 3063cfd0c0dSAlex Voicu 3070098f2aeSIlia Diachkov MachineInstr *getDefInstrMaybeConstant(Register &ConstReg, 3080098f2aeSIlia Diachkov const MachineRegisterInfo *MRI) { 309f6aa5087SVyacheslav Levytskyy MachineInstr *MI = MRI->getVRegDef(ConstReg); 310f6aa5087SVyacheslav Levytskyy MachineInstr *ConstInstr = 311f6aa5087SVyacheslav Levytskyy MI->getOpcode() == SPIRV::G_TRUNC || MI->getOpcode() == SPIRV::G_ZEXT 312f6aa5087SVyacheslav Levytskyy ? MRI->getVRegDef(MI->getOperand(1).getReg()) 313f6aa5087SVyacheslav Levytskyy : MI; 3147c760b22SSameer Sahasrabuddhe if (auto *GI = dyn_cast<GIntrinsic>(ConstInstr)) { 3157c760b22SSameer Sahasrabuddhe if (GI->is(Intrinsic::spv_track_constant)) { 3160098f2aeSIlia Diachkov ConstReg = ConstInstr->getOperand(2).getReg(); 3177c760b22SSameer Sahasrabuddhe return MRI->getVRegDef(ConstReg); 3187c760b22SSameer Sahasrabuddhe } 3190098f2aeSIlia Diachkov } else if (ConstInstr->getOpcode() == SPIRV::ASSIGN_TYPE) { 3200098f2aeSIlia Diachkov ConstReg = ConstInstr->getOperand(1).getReg(); 3217c760b22SSameer Sahasrabuddhe return MRI->getVRegDef(ConstReg); 3220098f2aeSIlia Diachkov } 323d9847cdeSSameer Sahasrabuddhe return MRI->getVRegDef(ConstReg); 3240098f2aeSIlia Diachkov } 3250098f2aeSIlia Diachkov 3260098f2aeSIlia Diachkov uint64_t getIConstVal(Register ConstReg, const MachineRegisterInfo *MRI) { 3270098f2aeSIlia Diachkov const MachineInstr *MI = getDefInstrMaybeConstant(ConstReg, MRI); 3280098f2aeSIlia Diachkov assert(MI && MI->getOpcode() == TargetOpcode::G_CONSTANT); 3290098f2aeSIlia Diachkov return MI->getOperand(1).getCImm()->getValue().getZExtValue(); 3300098f2aeSIlia Diachkov } 3310098f2aeSIlia Diachkov 332a9ffc92fSNathan Gauër bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID) { 333a9ffc92fSNathan Gauër if (const auto *GI = dyn_cast<GIntrinsic>(&MI)) 3347c760b22SSameer Sahasrabuddhe return GI->is(IntrinsicID); 3357c760b22SSameer Sahasrabuddhe return false; 336b8e1544bSIlia Diachkov } 337b8e1544bSIlia Diachkov 3380098f2aeSIlia Diachkov Type *getMDOperandAsType(const MDNode *N, unsigned I) { 339f7680835SVyacheslav Levytskyy Type *ElementTy = cast<ValueAsMetadata>(N->getOperand(I))->getType(); 3409a737109SVyacheslav Levytskyy return toTypedPointer(ElementTy); 3410098f2aeSIlia Diachkov } 342f61eb416SIlia Diachkov 343f61eb416SIlia Diachkov // The set of names is borrowed from the SPIR-V translator. 344f61eb416SIlia Diachkov // TODO: may be implemented in SPIRVBuiltins.td. 345f61eb416SIlia Diachkov static bool isPipeOrAddressSpaceCastBI(const StringRef MangledName) { 346f61eb416SIlia Diachkov return MangledName == "write_pipe_2" || MangledName == "read_pipe_2" || 347f61eb416SIlia Diachkov MangledName == "write_pipe_2_bl" || MangledName == "read_pipe_2_bl" || 348f61eb416SIlia Diachkov MangledName == "write_pipe_4" || MangledName == "read_pipe_4" || 349f61eb416SIlia Diachkov MangledName == "reserve_write_pipe" || 350f61eb416SIlia Diachkov MangledName == "reserve_read_pipe" || 351f61eb416SIlia Diachkov MangledName == "commit_write_pipe" || 352f61eb416SIlia Diachkov MangledName == "commit_read_pipe" || 353f61eb416SIlia Diachkov MangledName == "work_group_reserve_write_pipe" || 354f61eb416SIlia Diachkov MangledName == "work_group_reserve_read_pipe" || 355f61eb416SIlia Diachkov MangledName == "work_group_commit_write_pipe" || 356f61eb416SIlia Diachkov MangledName == "work_group_commit_read_pipe" || 357f61eb416SIlia Diachkov MangledName == "get_pipe_num_packets_ro" || 358f61eb416SIlia Diachkov MangledName == "get_pipe_max_packets_ro" || 359f61eb416SIlia Diachkov MangledName == "get_pipe_num_packets_wo" || 360f61eb416SIlia Diachkov MangledName == "get_pipe_max_packets_wo" || 361f61eb416SIlia Diachkov MangledName == "sub_group_reserve_write_pipe" || 362f61eb416SIlia Diachkov MangledName == "sub_group_reserve_read_pipe" || 363f61eb416SIlia Diachkov MangledName == "sub_group_commit_write_pipe" || 364f61eb416SIlia Diachkov MangledName == "sub_group_commit_read_pipe" || 365f61eb416SIlia Diachkov MangledName == "to_global" || MangledName == "to_local" || 366f61eb416SIlia Diachkov MangledName == "to_private"; 367f61eb416SIlia Diachkov } 368f61eb416SIlia Diachkov 369f61eb416SIlia Diachkov static bool isEnqueueKernelBI(const StringRef MangledName) { 370f61eb416SIlia Diachkov return MangledName == "__enqueue_kernel_basic" || 371f61eb416SIlia Diachkov MangledName == "__enqueue_kernel_basic_events" || 372f61eb416SIlia Diachkov MangledName == "__enqueue_kernel_varargs" || 373f61eb416SIlia Diachkov MangledName == "__enqueue_kernel_events_varargs"; 374f61eb416SIlia Diachkov } 375f61eb416SIlia Diachkov 376f61eb416SIlia Diachkov static bool isKernelQueryBI(const StringRef MangledName) { 377f61eb416SIlia Diachkov return MangledName == "__get_kernel_work_group_size_impl" || 378f61eb416SIlia Diachkov MangledName == "__get_kernel_sub_group_count_for_ndrange_impl" || 379f61eb416SIlia Diachkov MangledName == "__get_kernel_max_sub_group_size_for_ndrange_impl" || 380f61eb416SIlia Diachkov MangledName == "__get_kernel_preferred_work_group_size_multiple_impl"; 381f61eb416SIlia Diachkov } 382f61eb416SIlia Diachkov 383f61eb416SIlia Diachkov static bool isNonMangledOCLBuiltin(StringRef Name) { 384395f9ce3SKazu Hirata if (!Name.starts_with("__")) 385f61eb416SIlia Diachkov return false; 386f61eb416SIlia Diachkov 387f61eb416SIlia Diachkov return isEnqueueKernelBI(Name) || isKernelQueryBI(Name) || 388f61eb416SIlia Diachkov isPipeOrAddressSpaceCastBI(Name.drop_front(2)) || 389f61eb416SIlia Diachkov Name == "__translate_sampler_initializer"; 390f61eb416SIlia Diachkov } 391f61eb416SIlia Diachkov 3923544d200SIlia Diachkov std::string getOclOrSpirvBuiltinDemangledName(StringRef Name) { 393f61eb416SIlia Diachkov bool IsNonMangledOCL = isNonMangledOCLBuiltin(Name); 394395f9ce3SKazu Hirata bool IsNonMangledSPIRV = Name.starts_with("__spirv_"); 395f0eb9083SNathan Gauër bool IsNonMangledHLSL = Name.starts_with("__hlsl_"); 396395f9ce3SKazu Hirata bool IsMangled = Name.starts_with("_Z"); 397f61eb416SIlia Diachkov 398f0eb9083SNathan Gauër // Otherwise use simple demangling to return the function name. 399f0eb9083SNathan Gauër if (IsNonMangledOCL || IsNonMangledSPIRV || IsNonMangledHLSL || !IsMangled) 400f0eb9083SNathan Gauër return Name.str(); 401f61eb416SIlia Diachkov 402f61eb416SIlia Diachkov // Try to use the itanium demangler. 4038e6b3cc4SFangrui Song if (char *DemangledName = itaniumDemangle(Name.data())) { 404f61eb416SIlia Diachkov std::string Result = DemangledName; 405f61eb416SIlia Diachkov free(DemangledName); 406f61eb416SIlia Diachkov return Result; 407f61eb416SIlia Diachkov } 408f61eb416SIlia Diachkov 409f61eb416SIlia Diachkov // Autocheck C++, maybe need to do explicit check of the source language. 410f61eb416SIlia Diachkov // OpenCL C++ built-ins are declared in cl namespace. 411f61eb416SIlia Diachkov // TODO: consider using 'St' abbriviation for cl namespace mangling. 412f61eb416SIlia Diachkov // Similar to ::std:: in C++. 413f61eb416SIlia Diachkov size_t Start, Len = 0; 414f61eb416SIlia Diachkov size_t DemangledNameLenStart = 2; 415395f9ce3SKazu Hirata if (Name.starts_with("_ZN")) { 416f61eb416SIlia Diachkov // Skip CV and ref qualifiers. 417f61eb416SIlia Diachkov size_t NameSpaceStart = Name.find_first_not_of("rVKRO", 3); 418f61eb416SIlia Diachkov // All built-ins are in the ::cl:: namespace. 419f61eb416SIlia Diachkov if (Name.substr(NameSpaceStart, 11) != "2cl7__spirv") 420f61eb416SIlia Diachkov return std::string(); 421f61eb416SIlia Diachkov DemangledNameLenStart = NameSpaceStart + 11; 422f61eb416SIlia Diachkov } 423f61eb416SIlia Diachkov Start = Name.find_first_not_of("0123456789", DemangledNameLenStart); 424f61eb416SIlia Diachkov Name.substr(DemangledNameLenStart, Start - DemangledNameLenStart) 425f61eb416SIlia Diachkov .getAsInteger(10, Len); 426f61eb416SIlia Diachkov return Name.substr(Start, Len).str(); 427f61eb416SIlia Diachkov } 4283544d200SIlia Diachkov 42981751905SMichal Paszkowski bool hasBuiltinTypePrefix(StringRef Name) { 43043222bd3SMichal Paszkowski if (Name.starts_with("opencl.") || Name.starts_with("ocl_") || 43143222bd3SMichal Paszkowski Name.starts_with("spirv.")) 4325ac69674SMichal Paszkowski return true; 4335ac69674SMichal Paszkowski return false; 4345ac69674SMichal Paszkowski } 4355ac69674SMichal Paszkowski 436748922b3SIlia Diachkov bool isSpecialOpaqueType(const Type *Ty) { 437b5132b7dSVyacheslav Levytskyy if (const TargetExtType *ExtTy = dyn_cast<TargetExtType>(Ty)) 438b5132b7dSVyacheslav Levytskyy return isTypedPointerWrapper(ExtTy) 439b5132b7dSVyacheslav Levytskyy ? false 440b5132b7dSVyacheslav Levytskyy : hasBuiltinTypePrefix(ExtTy->getName()); 4415ac69674SMichal Paszkowski 4423544d200SIlia Diachkov return false; 4433544d200SIlia Diachkov } 4448e8f9c0bSVyacheslav Levytskyy 4458e8f9c0bSVyacheslav Levytskyy bool isEntryPoint(const Function &F) { 4468e8f9c0bSVyacheslav Levytskyy // OpenCL handling: any function with the SPIR_KERNEL 4478e8f9c0bSVyacheslav Levytskyy // calling convention will be a potential entry point. 4488e8f9c0bSVyacheslav Levytskyy if (F.getCallingConv() == CallingConv::SPIR_KERNEL) 4498e8f9c0bSVyacheslav Levytskyy return true; 4508e8f9c0bSVyacheslav Levytskyy 4518e8f9c0bSVyacheslav Levytskyy // HLSL handling: special attribute are emitted from the 4528e8f9c0bSVyacheslav Levytskyy // front-end. 4538e8f9c0bSVyacheslav Levytskyy if (F.getFnAttribute("hlsl.shader").isValid()) 4548e8f9c0bSVyacheslav Levytskyy return true; 4558e8f9c0bSVyacheslav Levytskyy 4568e8f9c0bSVyacheslav Levytskyy return false; 4578e8f9c0bSVyacheslav Levytskyy } 45843222bd3SMichal Paszkowski 459eb989f62SVyacheslav Levytskyy Type *parseBasicTypeName(StringRef &TypeName, LLVMContext &Ctx) { 46043222bd3SMichal Paszkowski TypeName.consume_front("atomic_"); 46143222bd3SMichal Paszkowski if (TypeName.consume_front("void")) 46243222bd3SMichal Paszkowski return Type::getVoidTy(Ctx); 463489db653SVyacheslav Levytskyy else if (TypeName.consume_front("bool") || TypeName.consume_front("_Bool")) 46443222bd3SMichal Paszkowski return Type::getIntNTy(Ctx, 1); 465335d5d5fSVyacheslav Levytskyy else if (TypeName.consume_front("char") || 466489db653SVyacheslav Levytskyy TypeName.consume_front("signed char") || 467335d5d5fSVyacheslav Levytskyy TypeName.consume_front("unsigned char") || 468335d5d5fSVyacheslav Levytskyy TypeName.consume_front("uchar")) 46943222bd3SMichal Paszkowski return Type::getInt8Ty(Ctx); 470335d5d5fSVyacheslav Levytskyy else if (TypeName.consume_front("short") || 471489db653SVyacheslav Levytskyy TypeName.consume_front("signed short") || 472335d5d5fSVyacheslav Levytskyy TypeName.consume_front("unsigned short") || 473335d5d5fSVyacheslav Levytskyy TypeName.consume_front("ushort")) 47443222bd3SMichal Paszkowski return Type::getInt16Ty(Ctx); 475335d5d5fSVyacheslav Levytskyy else if (TypeName.consume_front("int") || 476489db653SVyacheslav Levytskyy TypeName.consume_front("signed int") || 477335d5d5fSVyacheslav Levytskyy TypeName.consume_front("unsigned int") || 478335d5d5fSVyacheslav Levytskyy TypeName.consume_front("uint")) 47943222bd3SMichal Paszkowski return Type::getInt32Ty(Ctx); 480335d5d5fSVyacheslav Levytskyy else if (TypeName.consume_front("long") || 481489db653SVyacheslav Levytskyy TypeName.consume_front("signed long") || 482335d5d5fSVyacheslav Levytskyy TypeName.consume_front("unsigned long") || 483335d5d5fSVyacheslav Levytskyy TypeName.consume_front("ulong")) 48443222bd3SMichal Paszkowski return Type::getInt64Ty(Ctx); 485489db653SVyacheslav Levytskyy else if (TypeName.consume_front("half") || 486489db653SVyacheslav Levytskyy TypeName.consume_front("_Float16") || 487489db653SVyacheslav Levytskyy TypeName.consume_front("__fp16")) 48843222bd3SMichal Paszkowski return Type::getHalfTy(Ctx); 48943222bd3SMichal Paszkowski else if (TypeName.consume_front("float")) 49043222bd3SMichal Paszkowski return Type::getFloatTy(Ctx); 49143222bd3SMichal Paszkowski else if (TypeName.consume_front("double")) 49243222bd3SMichal Paszkowski return Type::getDoubleTy(Ctx); 49343222bd3SMichal Paszkowski 49443222bd3SMichal Paszkowski // Unable to recognize SPIRV type name 49543222bd3SMichal Paszkowski return nullptr; 49643222bd3SMichal Paszkowski } 49743222bd3SMichal Paszkowski 4981ed65febSNathan Gauër std::unordered_set<BasicBlock *> 4991ed65febSNathan Gauër PartialOrderingVisitor::getReachableFrom(BasicBlock *Start) { 5001ed65febSNathan Gauër std::queue<BasicBlock *> ToVisit; 5011ed65febSNathan Gauër ToVisit.push(Start); 5021ed65febSNathan Gauër 5031ed65febSNathan Gauër std::unordered_set<BasicBlock *> Output; 5041ed65febSNathan Gauër while (ToVisit.size() != 0) { 5051ed65febSNathan Gauër BasicBlock *BB = ToVisit.front(); 5061ed65febSNathan Gauër ToVisit.pop(); 5071ed65febSNathan Gauër 5081ed65febSNathan Gauër if (Output.count(BB) != 0) 5091ed65febSNathan Gauër continue; 5101ed65febSNathan Gauër Output.insert(BB); 5111ed65febSNathan Gauër 5121ed65febSNathan Gauër for (BasicBlock *Successor : successors(BB)) { 5131ed65febSNathan Gauër if (DT.dominates(Successor, BB)) 5141ed65febSNathan Gauër continue; 5151ed65febSNathan Gauër ToVisit.push(Successor); 5161ed65febSNathan Gauër } 5171ed65febSNathan Gauër } 5181ed65febSNathan Gauër 5191ed65febSNathan Gauër return Output; 5201ed65febSNathan Gauër } 5211ed65febSNathan Gauër 522cba70550SNathan Gauër bool PartialOrderingVisitor::CanBeVisited(BasicBlock *BB) const { 523cba70550SNathan Gauër for (BasicBlock *P : predecessors(BB)) { 524cba70550SNathan Gauër // Ignore back-edges. 525cba70550SNathan Gauër if (DT.dominates(BB, P)) 526cba70550SNathan Gauër continue; 5271ed65febSNathan Gauër 528cba70550SNathan Gauër // One of the predecessor hasn't been visited. Not ready yet. 529cba70550SNathan Gauër if (BlockToOrder.count(P) == 0) 530cba70550SNathan Gauër return false; 5311ed65febSNathan Gauër 532cba70550SNathan Gauër // If the block is a loop exit, the loop must be finished before 533cba70550SNathan Gauër // we can continue. 534cba70550SNathan Gauër Loop *L = LI.getLoopFor(P); 535cba70550SNathan Gauër if (L == nullptr || L->contains(BB)) 536cba70550SNathan Gauër continue; 537cba70550SNathan Gauër 538cba70550SNathan Gauër // SPIR-V requires a single back-edge. And the backend first 539cba70550SNathan Gauër // step transforms loops into the simplified format. If we have 540cba70550SNathan Gauër // more than 1 back-edge, something is wrong. 541cba70550SNathan Gauër assert(L->getNumBackEdges() <= 1); 542cba70550SNathan Gauër 543cba70550SNathan Gauër // If the loop has no latch, loop's rank won't matter, so we can 544cba70550SNathan Gauër // proceed. 545cba70550SNathan Gauër BasicBlock *Latch = L->getLoopLatch(); 546cba70550SNathan Gauër assert(Latch); 547cba70550SNathan Gauër if (Latch == nullptr) 548cba70550SNathan Gauër continue; 549cba70550SNathan Gauër 550cba70550SNathan Gauër // The latch is not ready yet, let's wait. 551cba70550SNathan Gauër if (BlockToOrder.count(Latch) == 0) 552cba70550SNathan Gauër return false; 553cba70550SNathan Gauër } 554cba70550SNathan Gauër 555cba70550SNathan Gauër return true; 556cba70550SNathan Gauër } 557cba70550SNathan Gauër 558cba70550SNathan Gauër size_t PartialOrderingVisitor::GetNodeRank(BasicBlock *BB) const { 55945b567beSNathan Gauër auto It = BlockToOrder.find(BB); 56045b567beSNathan Gauër if (It != BlockToOrder.end()) 56145b567beSNathan Gauër return It->second.Rank; 562cba70550SNathan Gauër 56345b567beSNathan Gauër size_t result = 0; 564cba70550SNathan Gauër for (BasicBlock *P : predecessors(BB)) { 565cba70550SNathan Gauër // Ignore back-edges. 566cba70550SNathan Gauër if (DT.dominates(BB, P)) 567cba70550SNathan Gauër continue; 568cba70550SNathan Gauër 569cba70550SNathan Gauër auto Iterator = BlockToOrder.end(); 570cba70550SNathan Gauër Loop *L = LI.getLoopFor(P); 571cba70550SNathan Gauër BasicBlock *Latch = L ? L->getLoopLatch() : nullptr; 572cba70550SNathan Gauër 573cba70550SNathan Gauër // If the predecessor is either outside a loop, or part of 574cba70550SNathan Gauër // the same loop, simply take its rank + 1. 575cba70550SNathan Gauër if (L == nullptr || L->contains(BB) || Latch == nullptr) { 576cba70550SNathan Gauër Iterator = BlockToOrder.find(P); 5771ed65febSNathan Gauër } else { 578cba70550SNathan Gauër // Otherwise, take the loop's rank (highest rank in the loop) as base. 579cba70550SNathan Gauër // Since loops have a single latch, highest rank is easy to find. 580cba70550SNathan Gauër // If the loop has no latch, then it doesn't matter. 581cba70550SNathan Gauër Iterator = BlockToOrder.find(Latch); 5821ed65febSNathan Gauër } 5831ed65febSNathan Gauër 584cba70550SNathan Gauër assert(Iterator != BlockToOrder.end()); 585cba70550SNathan Gauër result = std::max(result, Iterator->second.Rank + 1); 586cba70550SNathan Gauër } 587cba70550SNathan Gauër 588cba70550SNathan Gauër return result; 589cba70550SNathan Gauër } 590cba70550SNathan Gauër 591cba70550SNathan Gauër size_t PartialOrderingVisitor::visit(BasicBlock *BB, size_t Unused) { 592cba70550SNathan Gauër ToVisit.push(BB); 593cba70550SNathan Gauër Queued.insert(BB); 594cba70550SNathan Gauër 59545b567beSNathan Gauër size_t QueueIndex = 0; 596cba70550SNathan Gauër while (ToVisit.size() != 0) { 597cba70550SNathan Gauër BasicBlock *BB = ToVisit.front(); 598cba70550SNathan Gauër ToVisit.pop(); 599cba70550SNathan Gauër 600cba70550SNathan Gauër if (!CanBeVisited(BB)) { 601cba70550SNathan Gauër ToVisit.push(BB); 602920ea4afSNathan Gauër if (QueueIndex >= ToVisit.size()) 603920ea4afSNathan Gauër llvm::report_fatal_error( 60445b567beSNathan Gauër "No valid candidate in the queue. Is the graph reducible?"); 60545b567beSNathan Gauër QueueIndex++; 6061ed65febSNathan Gauër continue; 6071ed65febSNathan Gauër } 6081ed65febSNathan Gauër 60945b567beSNathan Gauër QueueIndex = 0; 610cba70550SNathan Gauër size_t Rank = GetNodeRank(BB); 611cba70550SNathan Gauër OrderInfo Info = {Rank, BlockToOrder.size()}; 612cba70550SNathan Gauër BlockToOrder.emplace(BB, Info); 6131ed65febSNathan Gauër 614cba70550SNathan Gauër for (BasicBlock *S : successors(BB)) { 615cba70550SNathan Gauër if (Queued.count(S) != 0) 6161ed65febSNathan Gauër continue; 617cba70550SNathan Gauër ToVisit.push(S); 618cba70550SNathan Gauër Queued.insert(S); 619cba70550SNathan Gauër } 6201ed65febSNathan Gauër } 6211ed65febSNathan Gauër 622cba70550SNathan Gauër return 0; 6231ed65febSNathan Gauër } 6241ed65febSNathan Gauër 6251ed65febSNathan Gauër PartialOrderingVisitor::PartialOrderingVisitor(Function &F) { 6261ed65febSNathan Gauër DT.recalculate(F); 6271ed65febSNathan Gauër LI = LoopInfo(DT); 6281ed65febSNathan Gauër 6291ed65febSNathan Gauër visit(&*F.begin(), 0); 6301ed65febSNathan Gauër 6311ed65febSNathan Gauër Order.reserve(F.size()); 6321ed65febSNathan Gauër for (auto &[BB, Info] : BlockToOrder) 6331ed65febSNathan Gauër Order.emplace_back(BB); 6341ed65febSNathan Gauër 6351ed65febSNathan Gauër std::sort(Order.begin(), Order.end(), [&](const auto &LHS, const auto &RHS) { 6361ed65febSNathan Gauër return compare(LHS, RHS); 6371ed65febSNathan Gauër }); 6381ed65febSNathan Gauër } 6391ed65febSNathan Gauër 6401ed65febSNathan Gauër bool PartialOrderingVisitor::compare(const BasicBlock *LHS, 6411ed65febSNathan Gauër const BasicBlock *RHS) const { 6421ed65febSNathan Gauër const OrderInfo &InfoLHS = BlockToOrder.at(const_cast<BasicBlock *>(LHS)); 6431ed65febSNathan Gauër const OrderInfo &InfoRHS = BlockToOrder.at(const_cast<BasicBlock *>(RHS)); 6441ed65febSNathan Gauër if (InfoLHS.Rank != InfoRHS.Rank) 6451ed65febSNathan Gauër return InfoLHS.Rank < InfoRHS.Rank; 6461ed65febSNathan Gauër return InfoLHS.TraversalIndex < InfoRHS.TraversalIndex; 6471ed65febSNathan Gauër } 6481ed65febSNathan Gauër 6491ed65febSNathan Gauër void PartialOrderingVisitor::partialOrderVisit( 6501ed65febSNathan Gauër BasicBlock &Start, std::function<bool(BasicBlock *)> Op) { 6511ed65febSNathan Gauër std::unordered_set<BasicBlock *> Reachable = getReachableFrom(&Start); 6521ed65febSNathan Gauër assert(BlockToOrder.count(&Start) != 0); 6531ed65febSNathan Gauër 6541ed65febSNathan Gauër // Skipping blocks with a rank inferior to |Start|'s rank. 6551ed65febSNathan Gauër auto It = Order.begin(); 6561ed65febSNathan Gauër while (It != Order.end() && *It != &Start) 6571ed65febSNathan Gauër ++It; 6581ed65febSNathan Gauër 6591ed65febSNathan Gauër // This is unexpected. Worst case |Start| is the last block, 6601ed65febSNathan Gauër // so It should point to the last block, not past-end. 6611ed65febSNathan Gauër assert(It != Order.end()); 6621ed65febSNathan Gauër 6631ed65febSNathan Gauër // By default, there is no rank limit. Setting it to the maximum value. 6641ed65febSNathan Gauër std::optional<size_t> EndRank = std::nullopt; 6651ed65febSNathan Gauër for (; It != Order.end(); ++It) { 6661ed65febSNathan Gauër if (EndRank.has_value() && BlockToOrder[*It].Rank > *EndRank) 6671ed65febSNathan Gauër break; 6681ed65febSNathan Gauër 6691ed65febSNathan Gauër if (Reachable.count(*It) == 0) { 6701ed65febSNathan Gauër continue; 6711ed65febSNathan Gauër } 6721ed65febSNathan Gauër 6731ed65febSNathan Gauër if (!Op(*It)) { 6741ed65febSNathan Gauër EndRank = BlockToOrder[*It].Rank; 6751ed65febSNathan Gauër } 6761ed65febSNathan Gauër } 6771ed65febSNathan Gauër } 6781ed65febSNathan Gauër 6791ed65febSNathan Gauër bool sortBlocks(Function &F) { 6801ed65febSNathan Gauër if (F.size() == 0) 6811ed65febSNathan Gauër return false; 6821ed65febSNathan Gauër 6831ed65febSNathan Gauër bool Modified = false; 6841ed65febSNathan Gauër std::vector<BasicBlock *> Order; 6851ed65febSNathan Gauër Order.reserve(F.size()); 6861ed65febSNathan Gauër 68753326ee0SNathan Gauër ReversePostOrderTraversal<Function *> RPOT(&F); 68853326ee0SNathan Gauër for (BasicBlock *BB : RPOT) 68953326ee0SNathan Gauër Order.push_back(BB); 6901ed65febSNathan Gauër 6911ed65febSNathan Gauër assert(&*F.begin() == Order[0]); 6921ed65febSNathan Gauër BasicBlock *LastBlock = &*F.begin(); 6931ed65febSNathan Gauër for (BasicBlock *BB : Order) { 6941ed65febSNathan Gauër if (BB != LastBlock && &*LastBlock->getNextNode() != BB) { 6951ed65febSNathan Gauër Modified = true; 6961ed65febSNathan Gauër BB->moveAfter(LastBlock); 6971ed65febSNathan Gauër } 6981ed65febSNathan Gauër LastBlock = BB; 6991ed65febSNathan Gauër } 7001ed65febSNathan Gauër 7011ed65febSNathan Gauër return Modified; 7021ed65febSNathan Gauër } 7031ed65febSNathan Gauër 704a059b299SVyacheslav Levytskyy MachineInstr *getVRegDef(MachineRegisterInfo &MRI, Register Reg) { 705a059b299SVyacheslav Levytskyy MachineInstr *MaybeDef = MRI.getVRegDef(Reg); 706a059b299SVyacheslav Levytskyy if (MaybeDef && MaybeDef->getOpcode() == SPIRV::ASSIGN_TYPE) 707a059b299SVyacheslav Levytskyy MaybeDef = MRI.getVRegDef(MaybeDef->getOperand(1).getReg()); 708a059b299SVyacheslav Levytskyy return MaybeDef; 709a059b299SVyacheslav Levytskyy } 710a059b299SVyacheslav Levytskyy 7118d8996ddSVyacheslav Levytskyy bool getVacantFunctionName(Module &M, std::string &Name) { 7128d8996ddSVyacheslav Levytskyy // It's a bit of paranoia, but still we don't want to have even a chance that 7138d8996ddSVyacheslav Levytskyy // the loop will work for too long. 7148d8996ddSVyacheslav Levytskyy constexpr unsigned MaxIters = 1024; 7158d8996ddSVyacheslav Levytskyy for (unsigned I = 0; I < MaxIters; ++I) { 7168d8996ddSVyacheslav Levytskyy std::string OrdName = Name + Twine(I).str(); 7178d8996ddSVyacheslav Levytskyy if (!M.getFunction(OrdName)) { 7188d8996ddSVyacheslav Levytskyy Name = OrdName; 7198d8996ddSVyacheslav Levytskyy return true; 7208d8996ddSVyacheslav Levytskyy } 7218d8996ddSVyacheslav Levytskyy } 7228d8996ddSVyacheslav Levytskyy return false; 7238d8996ddSVyacheslav Levytskyy } 7248d8996ddSVyacheslav Levytskyy 725b5132b7dSVyacheslav Levytskyy // Assign SPIR-V type to the register. If the register has no valid assigned 726b5132b7dSVyacheslav Levytskyy // class, set register LLT type and class according to the SPIR-V type. 727b5132b7dSVyacheslav Levytskyy void setRegClassType(Register Reg, SPIRVType *SpvType, SPIRVGlobalRegistry *GR, 728b5132b7dSVyacheslav Levytskyy MachineRegisterInfo *MRI, const MachineFunction &MF, 729b5132b7dSVyacheslav Levytskyy bool Force) { 730b5132b7dSVyacheslav Levytskyy GR->assignSPIRVTypeToVReg(SpvType, Reg, MF); 731b5132b7dSVyacheslav Levytskyy if (!MRI->getRegClassOrNull(Reg) || Force) { 732b5132b7dSVyacheslav Levytskyy MRI->setRegClass(Reg, GR->getRegClass(SpvType)); 733b5132b7dSVyacheslav Levytskyy MRI->setType(Reg, GR->getRegType(SpvType)); 734b5132b7dSVyacheslav Levytskyy } 735b5132b7dSVyacheslav Levytskyy } 736b5132b7dSVyacheslav Levytskyy 737b5132b7dSVyacheslav Levytskyy // Create a SPIR-V type, assign SPIR-V type to the register. If the register has 738b5132b7dSVyacheslav Levytskyy // no valid assigned class, set register LLT type and class according to the 739b5132b7dSVyacheslav Levytskyy // SPIR-V type. 740b5132b7dSVyacheslav Levytskyy void setRegClassType(Register Reg, const Type *Ty, SPIRVGlobalRegistry *GR, 741b5132b7dSVyacheslav Levytskyy MachineIRBuilder &MIRBuilder, bool Force) { 742b5132b7dSVyacheslav Levytskyy setRegClassType(Reg, GR->getOrCreateSPIRVType(Ty, MIRBuilder), GR, 743b5132b7dSVyacheslav Levytskyy MIRBuilder.getMRI(), MIRBuilder.getMF(), Force); 744b5132b7dSVyacheslav Levytskyy } 745b5132b7dSVyacheslav Levytskyy 746b5132b7dSVyacheslav Levytskyy // Create a virtual register and assign SPIR-V type to the register. Set 747b5132b7dSVyacheslav Levytskyy // register LLT type and class according to the SPIR-V type. 748b5132b7dSVyacheslav Levytskyy Register createVirtualRegister(SPIRVType *SpvType, SPIRVGlobalRegistry *GR, 749b5132b7dSVyacheslav Levytskyy MachineRegisterInfo *MRI, 750b5132b7dSVyacheslav Levytskyy const MachineFunction &MF) { 751b5132b7dSVyacheslav Levytskyy Register Reg = MRI->createVirtualRegister(GR->getRegClass(SpvType)); 752b5132b7dSVyacheslav Levytskyy MRI->setType(Reg, GR->getRegType(SpvType)); 753b5132b7dSVyacheslav Levytskyy GR->assignSPIRVTypeToVReg(SpvType, Reg, MF); 754b5132b7dSVyacheslav Levytskyy return Reg; 755b5132b7dSVyacheslav Levytskyy } 756b5132b7dSVyacheslav Levytskyy 757b5132b7dSVyacheslav Levytskyy // Create a virtual register and assign SPIR-V type to the register. Set 758b5132b7dSVyacheslav Levytskyy // register LLT type and class according to the SPIR-V type. 759b5132b7dSVyacheslav Levytskyy Register createVirtualRegister(SPIRVType *SpvType, SPIRVGlobalRegistry *GR, 760b5132b7dSVyacheslav Levytskyy MachineIRBuilder &MIRBuilder) { 761b5132b7dSVyacheslav Levytskyy return createVirtualRegister(SpvType, GR, MIRBuilder.getMRI(), 762b5132b7dSVyacheslav Levytskyy MIRBuilder.getMF()); 763b5132b7dSVyacheslav Levytskyy } 764b5132b7dSVyacheslav Levytskyy 765b5132b7dSVyacheslav Levytskyy // Create a SPIR-V type, virtual register and assign SPIR-V type to the 766b5132b7dSVyacheslav Levytskyy // register. Set register LLT type and class according to the SPIR-V type. 767b5132b7dSVyacheslav Levytskyy Register createVirtualRegister(const Type *Ty, SPIRVGlobalRegistry *GR, 768b5132b7dSVyacheslav Levytskyy MachineIRBuilder &MIRBuilder) { 769b5132b7dSVyacheslav Levytskyy return createVirtualRegister(GR->getOrCreateSPIRVType(Ty, MIRBuilder), GR, 770b5132b7dSVyacheslav Levytskyy MIRBuilder); 771b5132b7dSVyacheslav Levytskyy } 772b5132b7dSVyacheslav Levytskyy 773b5132b7dSVyacheslav Levytskyy // Return true if there is an opaque pointer type nested in the argument. 774b5132b7dSVyacheslav Levytskyy bool isNestedPointer(const Type *Ty) { 775b5132b7dSVyacheslav Levytskyy if (Ty->isPtrOrPtrVectorTy()) 776b5132b7dSVyacheslav Levytskyy return true; 777b5132b7dSVyacheslav Levytskyy if (const FunctionType *RefTy = dyn_cast<FunctionType>(Ty)) { 778b5132b7dSVyacheslav Levytskyy if (isNestedPointer(RefTy->getReturnType())) 779b5132b7dSVyacheslav Levytskyy return true; 780b5132b7dSVyacheslav Levytskyy for (const Type *ArgTy : RefTy->params()) 781b5132b7dSVyacheslav Levytskyy if (isNestedPointer(ArgTy)) 782b5132b7dSVyacheslav Levytskyy return true; 783b5132b7dSVyacheslav Levytskyy return false; 784b5132b7dSVyacheslav Levytskyy } 785b5132b7dSVyacheslav Levytskyy if (const ArrayType *RefTy = dyn_cast<ArrayType>(Ty)) 786b5132b7dSVyacheslav Levytskyy return isNestedPointer(RefTy->getElementType()); 787b5132b7dSVyacheslav Levytskyy return false; 788b5132b7dSVyacheslav Levytskyy } 789b5132b7dSVyacheslav Levytskyy 790b5132b7dSVyacheslav Levytskyy bool isSpvIntrinsic(const Value *Arg) { 791b5132b7dSVyacheslav Levytskyy if (const auto *II = dyn_cast<IntrinsicInst>(Arg)) 792b5132b7dSVyacheslav Levytskyy if (Function *F = II->getCalledFunction()) 793b5132b7dSVyacheslav Levytskyy if (F->getName().starts_with("llvm.spv.")) 794b5132b7dSVyacheslav Levytskyy return true; 795b5132b7dSVyacheslav Levytskyy return false; 796b5132b7dSVyacheslav Levytskyy } 797b5132b7dSVyacheslav Levytskyy 798b25b507cSIlia Diachkov } // namespace llvm 799