xref: /llvm-project/llvm/lib/Target/SPIRV/SPIRVUtils.cpp (revision 3ed2a81358e11a582eb5cc3edf711447767036e6)
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