1153dee34SIlia Diachkov //===- SPIRVModuleAnalysis.cpp - analysis of global instrs & regs - C++ -*-===//
2153dee34SIlia Diachkov //
3153dee34SIlia Diachkov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4153dee34SIlia Diachkov // See https://llvm.org/LICENSE.txt for license information.
5153dee34SIlia Diachkov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6153dee34SIlia Diachkov //
7153dee34SIlia Diachkov //===----------------------------------------------------------------------===//
8153dee34SIlia Diachkov //
9153dee34SIlia Diachkov // The analysis collects instructions that should be output at the module level
10153dee34SIlia Diachkov // and performs the global register numbering.
11153dee34SIlia Diachkov //
12153dee34SIlia Diachkov // The results of this analysis are used in AsmPrinter to rename registers
13153dee34SIlia Diachkov // globally and to output required instructions at the module level.
14153dee34SIlia Diachkov //
15153dee34SIlia Diachkov //===----------------------------------------------------------------------===//
16153dee34SIlia Diachkov 
17153dee34SIlia Diachkov #include "SPIRVModuleAnalysis.h"
18153dee34SIlia Diachkov #include "SPIRV.h"
19153dee34SIlia Diachkov #include "SPIRVGlobalRegistry.h"
20153dee34SIlia Diachkov #include "SPIRVSubtarget.h"
21153dee34SIlia Diachkov #include "SPIRVTargetMachine.h"
22153dee34SIlia Diachkov #include "SPIRVUtils.h"
23153dee34SIlia Diachkov #include "TargetInfo/SPIRVTargetInfo.h"
24153dee34SIlia Diachkov #include "llvm/CodeGen/MachineModuleInfo.h"
25153dee34SIlia Diachkov #include "llvm/CodeGen/TargetPassConfig.h"
26153dee34SIlia Diachkov 
27153dee34SIlia Diachkov using namespace llvm;
28153dee34SIlia Diachkov 
29153dee34SIlia Diachkov #define DEBUG_TYPE "spirv-module-analysis"
30153dee34SIlia Diachkov 
31fa2a7a25SAleksandr Bezzubikov static cl::opt<bool>
32fa2a7a25SAleksandr Bezzubikov     SPVDumpDeps("spv-dump-deps",
33fa2a7a25SAleksandr Bezzubikov                 cl::desc("Dump MIR with SPIR-V dependencies info"),
34fa2a7a25SAleksandr Bezzubikov                 cl::Optional, cl::init(false));
35fa2a7a25SAleksandr Bezzubikov 
36153dee34SIlia Diachkov char llvm::SPIRVModuleAnalysis::ID = 0;
37153dee34SIlia Diachkov 
38153dee34SIlia Diachkov namespace llvm {
39153dee34SIlia Diachkov void initializeSPIRVModuleAnalysisPass(PassRegistry &);
40153dee34SIlia Diachkov } // namespace llvm
41153dee34SIlia Diachkov 
42153dee34SIlia Diachkov INITIALIZE_PASS(SPIRVModuleAnalysis, DEBUG_TYPE, "SPIRV module analysis", true,
43153dee34SIlia Diachkov                 true)
44153dee34SIlia Diachkov 
45153dee34SIlia Diachkov // Retrieve an unsigned from an MDNode with a list of them as operands.
getMetadataUInt(MDNode * MdNode,unsigned OpIndex,unsigned DefaultVal=0)46153dee34SIlia Diachkov static unsigned getMetadataUInt(MDNode *MdNode, unsigned OpIndex,
47153dee34SIlia Diachkov                                 unsigned DefaultVal = 0) {
48153dee34SIlia Diachkov   if (MdNode && OpIndex < MdNode->getNumOperands()) {
49153dee34SIlia Diachkov     const auto &Op = MdNode->getOperand(OpIndex);
50153dee34SIlia Diachkov     return mdconst::extract<ConstantInt>(Op)->getZExtValue();
51153dee34SIlia Diachkov   }
52153dee34SIlia Diachkov   return DefaultVal;
53153dee34SIlia Diachkov }
54153dee34SIlia Diachkov 
setBaseInfo(const Module & M)55153dee34SIlia Diachkov void SPIRVModuleAnalysis::setBaseInfo(const Module &M) {
56153dee34SIlia Diachkov   MAI.MaxID = 0;
57153dee34SIlia Diachkov   for (int i = 0; i < SPIRV::NUM_MODULE_SECTIONS; i++)
58153dee34SIlia Diachkov     MAI.MS[i].clear();
59153dee34SIlia Diachkov   MAI.RegisterAliasTable.clear();
60153dee34SIlia Diachkov   MAI.InstrsToDelete.clear();
61153dee34SIlia Diachkov   MAI.FuncNameMap.clear();
62153dee34SIlia Diachkov   MAI.GlobalVarList.clear();
63*b8e1544bSIlia Diachkov   MAI.ExtInstSetMap.clear();
64153dee34SIlia Diachkov 
65153dee34SIlia Diachkov   // TODO: determine memory model and source language from the configuratoin.
66*b8e1544bSIlia Diachkov   if (auto MemModel = M.getNamedMetadata("spirv.MemoryModel")) {
67*b8e1544bSIlia Diachkov     auto MemMD = MemModel->getOperand(0);
68*b8e1544bSIlia Diachkov     MAI.Addr = static_cast<SPIRV::AddressingModel>(getMetadataUInt(MemMD, 0));
69*b8e1544bSIlia Diachkov     MAI.Mem = static_cast<SPIRV::MemoryModel>(getMetadataUInt(MemMD, 1));
70*b8e1544bSIlia Diachkov   } else {
71153dee34SIlia Diachkov     MAI.Mem = SPIRV::MemoryModel::OpenCL;
72153dee34SIlia Diachkov     unsigned PtrSize = ST->getPointerSize();
73153dee34SIlia Diachkov     MAI.Addr = PtrSize == 32   ? SPIRV::AddressingModel::Physical32
74153dee34SIlia Diachkov                : PtrSize == 64 ? SPIRV::AddressingModel::Physical64
75153dee34SIlia Diachkov                                : SPIRV::AddressingModel::Logical;
76*b8e1544bSIlia Diachkov   }
77153dee34SIlia Diachkov   // Get the OpenCL version number from metadata.
78153dee34SIlia Diachkov   // TODO: support other source languages.
79153dee34SIlia Diachkov   if (auto VerNode = M.getNamedMetadata("opencl.ocl.version")) {
80*b8e1544bSIlia Diachkov     MAI.SrcLang = SPIRV::SourceLanguage::OpenCL_C;
81*b8e1544bSIlia Diachkov     // Construct version literal in accordance with SPIRV-LLVM-Translator.
82*b8e1544bSIlia Diachkov     // TODO: support multiple OCL version metadata.
83*b8e1544bSIlia Diachkov     assert(VerNode->getNumOperands() > 0 && "Invalid SPIR");
84153dee34SIlia Diachkov     auto VersionMD = VerNode->getOperand(0);
85153dee34SIlia Diachkov     unsigned MajorNum = getMetadataUInt(VersionMD, 0, 2);
86153dee34SIlia Diachkov     unsigned MinorNum = getMetadataUInt(VersionMD, 1);
87153dee34SIlia Diachkov     unsigned RevNum = getMetadataUInt(VersionMD, 2);
88*b8e1544bSIlia Diachkov     MAI.SrcLangVersion = (MajorNum * 100 + MinorNum) * 1000 + RevNum;
89*b8e1544bSIlia Diachkov   } else {
90*b8e1544bSIlia Diachkov     MAI.SrcLang = SPIRV::SourceLanguage::Unknown;
91*b8e1544bSIlia Diachkov     MAI.SrcLangVersion = 0;
92*b8e1544bSIlia Diachkov   }
93*b8e1544bSIlia Diachkov 
94*b8e1544bSIlia Diachkov   if (auto ExtNode = M.getNamedMetadata("opencl.used.extensions")) {
95*b8e1544bSIlia Diachkov     for (unsigned I = 0, E = ExtNode->getNumOperands(); I != E; ++I) {
96*b8e1544bSIlia Diachkov       MDNode *MD = ExtNode->getOperand(I);
97*b8e1544bSIlia Diachkov       if (!MD || MD->getNumOperands() == 0)
98*b8e1544bSIlia Diachkov         continue;
99*b8e1544bSIlia Diachkov       for (unsigned J = 0, N = MD->getNumOperands(); J != N; ++J)
100*b8e1544bSIlia Diachkov         MAI.SrcExt.insert(cast<MDString>(MD->getOperand(J))->getString());
101153dee34SIlia Diachkov     }
102153dee34SIlia Diachkov   }
103153dee34SIlia Diachkov 
104*b8e1544bSIlia Diachkov   // TODO: check if it's required by default.
105*b8e1544bSIlia Diachkov   MAI.ExtInstSetMap[static_cast<unsigned>(SPIRV::InstructionSet::OpenCL_std)] =
106*b8e1544bSIlia Diachkov       Register::index2VirtReg(MAI.getNextID());
107153dee34SIlia Diachkov }
108153dee34SIlia Diachkov 
109fa2a7a25SAleksandr Bezzubikov // Collect MI which defines the register in the given machine function.
collectDefInstr(Register Reg,const MachineFunction * MF,SPIRV::ModuleAnalysisInfo * MAI,SPIRV::ModuleSectionType MSType,bool DoInsert=true)110fa2a7a25SAleksandr Bezzubikov static void collectDefInstr(Register Reg, const MachineFunction *MF,
111fa2a7a25SAleksandr Bezzubikov                             SPIRV::ModuleAnalysisInfo *MAI,
112fa2a7a25SAleksandr Bezzubikov                             SPIRV::ModuleSectionType MSType,
113fa2a7a25SAleksandr Bezzubikov                             bool DoInsert = true) {
114fa2a7a25SAleksandr Bezzubikov   assert(MAI->hasRegisterAlias(MF, Reg) && "Cannot find register alias");
115fa2a7a25SAleksandr Bezzubikov   MachineInstr *MI = MF->getRegInfo().getUniqueVRegDef(Reg);
116fa2a7a25SAleksandr Bezzubikov   assert(MI && "There should be an instruction that defines the register");
117fa2a7a25SAleksandr Bezzubikov   MAI->setSkipEmission(MI);
118fa2a7a25SAleksandr Bezzubikov   if (DoInsert)
119fa2a7a25SAleksandr Bezzubikov     MAI->MS[MSType].push_back(MI);
120fa2a7a25SAleksandr Bezzubikov }
121fa2a7a25SAleksandr Bezzubikov 
collectGlobalEntities(const std::vector<SPIRV::DTSortableEntry * > & DepsGraph,SPIRV::ModuleSectionType MSType,std::function<bool (const SPIRV::DTSortableEntry *)> Pred,bool UsePreOrder=false)122fa2a7a25SAleksandr Bezzubikov void SPIRVModuleAnalysis::collectGlobalEntities(
123fa2a7a25SAleksandr Bezzubikov     const std::vector<SPIRV::DTSortableEntry *> &DepsGraph,
124fa2a7a25SAleksandr Bezzubikov     SPIRV::ModuleSectionType MSType,
125fa2a7a25SAleksandr Bezzubikov     std::function<bool(const SPIRV::DTSortableEntry *)> Pred,
126*b8e1544bSIlia Diachkov     bool UsePreOrder = false) {
127fa2a7a25SAleksandr Bezzubikov   DenseSet<const SPIRV::DTSortableEntry *> Visited;
128fa2a7a25SAleksandr Bezzubikov   for (const auto *E : DepsGraph) {
129fa2a7a25SAleksandr Bezzubikov     std::function<void(const SPIRV::DTSortableEntry *)> RecHoistUtil;
130fa2a7a25SAleksandr Bezzubikov     // NOTE: here we prefer recursive approach over iterative because
131fa2a7a25SAleksandr Bezzubikov     // we don't expect depchains long enough to cause SO.
132fa2a7a25SAleksandr Bezzubikov     RecHoistUtil = [MSType, UsePreOrder, &Visited, &Pred,
133fa2a7a25SAleksandr Bezzubikov                     &RecHoistUtil](const SPIRV::DTSortableEntry *E) {
134fa2a7a25SAleksandr Bezzubikov       if (Visited.count(E) || !Pred(E))
135fa2a7a25SAleksandr Bezzubikov         return;
136fa2a7a25SAleksandr Bezzubikov       Visited.insert(E);
137fa2a7a25SAleksandr Bezzubikov 
138fa2a7a25SAleksandr Bezzubikov       // Traversing deps graph in post-order allows us to get rid of
139fa2a7a25SAleksandr Bezzubikov       // register aliases preprocessing.
140fa2a7a25SAleksandr Bezzubikov       // But pre-order is required for correct processing of function
141fa2a7a25SAleksandr Bezzubikov       // declaration and arguments processing.
142fa2a7a25SAleksandr Bezzubikov       if (!UsePreOrder)
143fa2a7a25SAleksandr Bezzubikov         for (auto *S : E->getDeps())
144fa2a7a25SAleksandr Bezzubikov           RecHoistUtil(S);
145fa2a7a25SAleksandr Bezzubikov 
146fa2a7a25SAleksandr Bezzubikov       Register GlobalReg = Register::index2VirtReg(MAI.getNextID());
147fa2a7a25SAleksandr Bezzubikov       bool IsFirst = true;
148fa2a7a25SAleksandr Bezzubikov       for (auto &U : *E) {
149fa2a7a25SAleksandr Bezzubikov         const MachineFunction *MF = U.first;
150fa2a7a25SAleksandr Bezzubikov         Register Reg = U.second;
151fa2a7a25SAleksandr Bezzubikov         MAI.setRegisterAlias(MF, Reg, GlobalReg);
152fa2a7a25SAleksandr Bezzubikov         if (!MF->getRegInfo().getUniqueVRegDef(Reg))
153fa2a7a25SAleksandr Bezzubikov           continue;
154fa2a7a25SAleksandr Bezzubikov         collectDefInstr(Reg, MF, &MAI, MSType, IsFirst);
155fa2a7a25SAleksandr Bezzubikov         IsFirst = false;
156fa2a7a25SAleksandr Bezzubikov         if (E->getIsGV())
157fa2a7a25SAleksandr Bezzubikov           MAI.GlobalVarList.push_back(MF->getRegInfo().getUniqueVRegDef(Reg));
158fa2a7a25SAleksandr Bezzubikov       }
159fa2a7a25SAleksandr Bezzubikov 
160fa2a7a25SAleksandr Bezzubikov       if (UsePreOrder)
161fa2a7a25SAleksandr Bezzubikov         for (auto *S : E->getDeps())
162fa2a7a25SAleksandr Bezzubikov           RecHoistUtil(S);
163fa2a7a25SAleksandr Bezzubikov     };
164fa2a7a25SAleksandr Bezzubikov     RecHoistUtil(E);
165fa2a7a25SAleksandr Bezzubikov   }
166fa2a7a25SAleksandr Bezzubikov }
167fa2a7a25SAleksandr Bezzubikov 
168fa2a7a25SAleksandr Bezzubikov // The function initializes global register alias table for types, consts,
169fa2a7a25SAleksandr Bezzubikov // global vars and func decls and collects these instruction for output
170fa2a7a25SAleksandr Bezzubikov // at module level. Also it collects explicit OpExtension/OpCapability
171fa2a7a25SAleksandr Bezzubikov // instructions.
processDefInstrs(const Module & M)172fa2a7a25SAleksandr Bezzubikov void SPIRVModuleAnalysis::processDefInstrs(const Module &M) {
173fa2a7a25SAleksandr Bezzubikov   std::vector<SPIRV::DTSortableEntry *> DepsGraph;
174fa2a7a25SAleksandr Bezzubikov 
175fa2a7a25SAleksandr Bezzubikov   GR->buildDepsGraph(DepsGraph, SPVDumpDeps ? MMI : nullptr);
176fa2a7a25SAleksandr Bezzubikov 
177fa2a7a25SAleksandr Bezzubikov   collectGlobalEntities(
178fa2a7a25SAleksandr Bezzubikov       DepsGraph, SPIRV::MB_TypeConstVars,
179*b8e1544bSIlia Diachkov       [](const SPIRV::DTSortableEntry *E) { return !E->getIsFunc(); });
180fa2a7a25SAleksandr Bezzubikov 
181fa2a7a25SAleksandr Bezzubikov   collectGlobalEntities(
182fa2a7a25SAleksandr Bezzubikov       DepsGraph, SPIRV::MB_ExtFuncDecls,
183fa2a7a25SAleksandr Bezzubikov       [](const SPIRV::DTSortableEntry *E) { return E->getIsFunc(); }, true);
184fa2a7a25SAleksandr Bezzubikov }
185fa2a7a25SAleksandr Bezzubikov 
186*b8e1544bSIlia Diachkov // True if there is an instruction in the MS list with all the same operands as
187*b8e1544bSIlia Diachkov // the given instruction has (after the given starting index).
188*b8e1544bSIlia Diachkov // TODO: maybe it needs to check Opcodes too.
findSameInstrInMS(const MachineInstr & A,SPIRV::ModuleSectionType MSType,SPIRV::ModuleAnalysisInfo & MAI,unsigned StartOpIndex=0)189*b8e1544bSIlia Diachkov static bool findSameInstrInMS(const MachineInstr &A,
190*b8e1544bSIlia Diachkov                               SPIRV::ModuleSectionType MSType,
191*b8e1544bSIlia Diachkov                               SPIRV::ModuleAnalysisInfo &MAI,
192*b8e1544bSIlia Diachkov                               unsigned StartOpIndex = 0) {
193*b8e1544bSIlia Diachkov   for (const auto *B : MAI.MS[MSType]) {
194*b8e1544bSIlia Diachkov     const unsigned NumAOps = A.getNumOperands();
195*b8e1544bSIlia Diachkov     if (NumAOps != B->getNumOperands() || A.getNumDefs() != B->getNumDefs())
196*b8e1544bSIlia Diachkov       continue;
197*b8e1544bSIlia Diachkov     bool AllOpsMatch = true;
198*b8e1544bSIlia Diachkov     for (unsigned i = StartOpIndex; i < NumAOps && AllOpsMatch; ++i) {
199*b8e1544bSIlia Diachkov       if (A.getOperand(i).isReg() && B->getOperand(i).isReg()) {
200*b8e1544bSIlia Diachkov         Register RegA = A.getOperand(i).getReg();
201*b8e1544bSIlia Diachkov         Register RegB = B->getOperand(i).getReg();
202*b8e1544bSIlia Diachkov         AllOpsMatch = MAI.getRegisterAlias(A.getMF(), RegA) ==
203*b8e1544bSIlia Diachkov                       MAI.getRegisterAlias(B->getMF(), RegB);
204*b8e1544bSIlia Diachkov       } else {
205*b8e1544bSIlia Diachkov         AllOpsMatch = A.getOperand(i).isIdenticalTo(B->getOperand(i));
206*b8e1544bSIlia Diachkov       }
207*b8e1544bSIlia Diachkov     }
208*b8e1544bSIlia Diachkov     if (AllOpsMatch)
209*b8e1544bSIlia Diachkov       return true;
210*b8e1544bSIlia Diachkov   }
211*b8e1544bSIlia Diachkov   return false;
212*b8e1544bSIlia Diachkov }
213*b8e1544bSIlia Diachkov 
214153dee34SIlia Diachkov // Look for IDs declared with Import linkage, and map the imported name string
215153dee34SIlia Diachkov // to the register defining that variable (which will usually be the result of
216153dee34SIlia Diachkov // an OpFunction). This lets us call externally imported functions using
217153dee34SIlia Diachkov // the correct ID registers.
collectFuncNames(MachineInstr & MI,const Function & F)218153dee34SIlia Diachkov void SPIRVModuleAnalysis::collectFuncNames(MachineInstr &MI,
219153dee34SIlia Diachkov                                            const Function &F) {
220153dee34SIlia Diachkov   if (MI.getOpcode() == SPIRV::OpDecorate) {
221153dee34SIlia Diachkov     // If it's got Import linkage.
222153dee34SIlia Diachkov     auto Dec = MI.getOperand(1).getImm();
223153dee34SIlia Diachkov     if (Dec == static_cast<unsigned>(SPIRV::Decoration::LinkageAttributes)) {
224153dee34SIlia Diachkov       auto Lnk = MI.getOperand(MI.getNumOperands() - 1).getImm();
225153dee34SIlia Diachkov       if (Lnk == static_cast<unsigned>(SPIRV::LinkageType::Import)) {
226153dee34SIlia Diachkov         // Map imported function name to function ID register.
227153dee34SIlia Diachkov         std::string Name = getStringImm(MI, 2);
228153dee34SIlia Diachkov         Register Target = MI.getOperand(0).getReg();
229153dee34SIlia Diachkov         // TODO: check defs from different MFs.
230153dee34SIlia Diachkov         MAI.FuncNameMap[Name] = MAI.getRegisterAlias(MI.getMF(), Target);
231153dee34SIlia Diachkov       }
232153dee34SIlia Diachkov     }
233153dee34SIlia Diachkov   } else if (MI.getOpcode() == SPIRV::OpFunction) {
234153dee34SIlia Diachkov     // Record all internal OpFunction declarations.
235153dee34SIlia Diachkov     Register Reg = MI.defs().begin()->getReg();
236153dee34SIlia Diachkov     Register GlobalReg = MAI.getRegisterAlias(MI.getMF(), Reg);
237153dee34SIlia Diachkov     assert(GlobalReg.isValid());
238153dee34SIlia Diachkov     // TODO: check that it does not conflict with existing entries.
239153dee34SIlia Diachkov     MAI.FuncNameMap[F.getGlobalIdentifier()] = GlobalReg;
240153dee34SIlia Diachkov   }
241153dee34SIlia Diachkov }
242153dee34SIlia Diachkov 
243153dee34SIlia Diachkov // Collect the given instruction in the specified MS. We assume global register
244153dee34SIlia Diachkov // numbering has already occurred by this point. We can directly compare reg
245153dee34SIlia Diachkov // arguments when detecting duplicates.
collectOtherInstr(MachineInstr & MI,SPIRV::ModuleAnalysisInfo & MAI,SPIRV::ModuleSectionType MSType,bool Append=true)246153dee34SIlia Diachkov static void collectOtherInstr(MachineInstr &MI, SPIRV::ModuleAnalysisInfo &MAI,
247*b8e1544bSIlia Diachkov                               SPIRV::ModuleSectionType MSType,
248*b8e1544bSIlia Diachkov                               bool Append = true) {
249153dee34SIlia Diachkov   MAI.setSkipEmission(&MI);
250*b8e1544bSIlia Diachkov   if (findSameInstrInMS(MI, MSType, MAI))
251153dee34SIlia Diachkov     return; // Found a duplicate, so don't add it.
252153dee34SIlia Diachkov   // No duplicates, so add it.
253*b8e1544bSIlia Diachkov   if (Append)
254153dee34SIlia Diachkov     MAI.MS[MSType].push_back(&MI);
255*b8e1544bSIlia Diachkov   else
256*b8e1544bSIlia Diachkov     MAI.MS[MSType].insert(MAI.MS[MSType].begin(), &MI);
257153dee34SIlia Diachkov }
258153dee34SIlia Diachkov 
259153dee34SIlia Diachkov // Some global instructions make reference to function-local ID regs, so cannot
260153dee34SIlia Diachkov // be correctly collected until these registers are globally numbered.
processOtherInstrs(const Module & M)261153dee34SIlia Diachkov void SPIRVModuleAnalysis::processOtherInstrs(const Module &M) {
262153dee34SIlia Diachkov   for (auto F = M.begin(), E = M.end(); F != E; ++F) {
263153dee34SIlia Diachkov     if ((*F).isDeclaration())
264153dee34SIlia Diachkov       continue;
265153dee34SIlia Diachkov     MachineFunction *MF = MMI->getMachineFunction(*F);
266153dee34SIlia Diachkov     assert(MF);
267153dee34SIlia Diachkov     for (MachineBasicBlock &MBB : *MF)
268153dee34SIlia Diachkov       for (MachineInstr &MI : MBB) {
269153dee34SIlia Diachkov         if (MAI.getSkipEmission(&MI))
270153dee34SIlia Diachkov           continue;
271153dee34SIlia Diachkov         const unsigned OpCode = MI.getOpcode();
272153dee34SIlia Diachkov         if (OpCode == SPIRV::OpName || OpCode == SPIRV::OpMemberName) {
273153dee34SIlia Diachkov           collectOtherInstr(MI, MAI, SPIRV::MB_DebugNames);
274153dee34SIlia Diachkov         } else if (OpCode == SPIRV::OpEntryPoint) {
275153dee34SIlia Diachkov           collectOtherInstr(MI, MAI, SPIRV::MB_EntryPoints);
276153dee34SIlia Diachkov         } else if (TII->isDecorationInstr(MI)) {
277153dee34SIlia Diachkov           collectOtherInstr(MI, MAI, SPIRV::MB_Annotations);
278153dee34SIlia Diachkov           collectFuncNames(MI, *F);
279*b8e1544bSIlia Diachkov         } else if (TII->isConstantInstr(MI)) {
280*b8e1544bSIlia Diachkov           // Now OpSpecConstant*s are not in DT,
281*b8e1544bSIlia Diachkov           // but they need to be collected anyway.
282*b8e1544bSIlia Diachkov           collectOtherInstr(MI, MAI, SPIRV::MB_TypeConstVars);
283153dee34SIlia Diachkov         } else if (OpCode == SPIRV::OpFunction) {
284153dee34SIlia Diachkov           collectFuncNames(MI, *F);
285*b8e1544bSIlia Diachkov         } else if (OpCode == SPIRV::OpTypeForwardPointer) {
286*b8e1544bSIlia Diachkov           collectOtherInstr(MI, MAI, SPIRV::MB_TypeConstVars, false);
287153dee34SIlia Diachkov         }
288153dee34SIlia Diachkov       }
289153dee34SIlia Diachkov   }
290153dee34SIlia Diachkov }
291153dee34SIlia Diachkov 
292153dee34SIlia Diachkov // Number registers in all functions globally from 0 onwards and store
293*b8e1544bSIlia Diachkov // the result in global register alias table. Some registers are already
294*b8e1544bSIlia Diachkov // numbered in collectGlobalEntities.
numberRegistersGlobally(const Module & M)295153dee34SIlia Diachkov void SPIRVModuleAnalysis::numberRegistersGlobally(const Module &M) {
296153dee34SIlia Diachkov   for (auto F = M.begin(), E = M.end(); F != E; ++F) {
297153dee34SIlia Diachkov     if ((*F).isDeclaration())
298153dee34SIlia Diachkov       continue;
299153dee34SIlia Diachkov     MachineFunction *MF = MMI->getMachineFunction(*F);
300153dee34SIlia Diachkov     assert(MF);
301153dee34SIlia Diachkov     for (MachineBasicBlock &MBB : *MF) {
302153dee34SIlia Diachkov       for (MachineInstr &MI : MBB) {
303153dee34SIlia Diachkov         for (MachineOperand &Op : MI.operands()) {
304153dee34SIlia Diachkov           if (!Op.isReg())
305153dee34SIlia Diachkov             continue;
306153dee34SIlia Diachkov           Register Reg = Op.getReg();
307153dee34SIlia Diachkov           if (MAI.hasRegisterAlias(MF, Reg))
308153dee34SIlia Diachkov             continue;
309153dee34SIlia Diachkov           Register NewReg = Register::index2VirtReg(MAI.getNextID());
310153dee34SIlia Diachkov           MAI.setRegisterAlias(MF, Reg, NewReg);
311153dee34SIlia Diachkov         }
312*b8e1544bSIlia Diachkov         if (MI.getOpcode() != SPIRV::OpExtInst)
313*b8e1544bSIlia Diachkov           continue;
314*b8e1544bSIlia Diachkov         auto Set = MI.getOperand(2).getImm();
315*b8e1544bSIlia Diachkov         if (MAI.ExtInstSetMap.find(Set) == MAI.ExtInstSetMap.end())
316*b8e1544bSIlia Diachkov           MAI.ExtInstSetMap[Set] = Register::index2VirtReg(MAI.getNextID());
317153dee34SIlia Diachkov       }
318153dee34SIlia Diachkov     }
319153dee34SIlia Diachkov   }
320153dee34SIlia Diachkov }
321153dee34SIlia Diachkov 
322*b8e1544bSIlia Diachkov // Find OpIEqual and OpBranchConditional instructions originating from
323*b8e1544bSIlia Diachkov // OpSwitches, mark them skipped for emission. Also mark MBB skipped if it
324*b8e1544bSIlia Diachkov // contains only these instructions.
processSwitches(const Module & M,SPIRV::ModuleAnalysisInfo & MAI,MachineModuleInfo * MMI)325*b8e1544bSIlia Diachkov static void processSwitches(const Module &M, SPIRV::ModuleAnalysisInfo &MAI,
326*b8e1544bSIlia Diachkov                             MachineModuleInfo *MMI) {
327*b8e1544bSIlia Diachkov   DenseSet<Register> SwitchRegs;
328*b8e1544bSIlia Diachkov   for (auto F = M.begin(), E = M.end(); F != E; ++F) {
329*b8e1544bSIlia Diachkov     MachineFunction *MF = MMI->getMachineFunction(*F);
330*b8e1544bSIlia Diachkov     if (!MF)
331*b8e1544bSIlia Diachkov       continue;
332*b8e1544bSIlia Diachkov     for (MachineBasicBlock &MBB : *MF)
333*b8e1544bSIlia Diachkov       for (MachineInstr &MI : MBB) {
334*b8e1544bSIlia Diachkov         if (MAI.getSkipEmission(&MI))
335*b8e1544bSIlia Diachkov           continue;
336*b8e1544bSIlia Diachkov         if (MI.getOpcode() == SPIRV::OpSwitch) {
337*b8e1544bSIlia Diachkov           assert(MI.getOperand(0).isReg());
338*b8e1544bSIlia Diachkov           SwitchRegs.insert(MI.getOperand(0).getReg());
339*b8e1544bSIlia Diachkov         }
340*b8e1544bSIlia Diachkov         if (MI.getOpcode() != SPIRV::OpIEqual || !MI.getOperand(2).isReg() ||
341*b8e1544bSIlia Diachkov             !SwitchRegs.contains(MI.getOperand(2).getReg()))
342*b8e1544bSIlia Diachkov           continue;
343*b8e1544bSIlia Diachkov         Register CmpReg = MI.getOperand(0).getReg();
344*b8e1544bSIlia Diachkov         MachineInstr *CBr = MI.getNextNode();
345*b8e1544bSIlia Diachkov         assert(CBr && CBr->getOpcode() == SPIRV::OpBranchConditional &&
346*b8e1544bSIlia Diachkov                CBr->getOperand(0).isReg() &&
347*b8e1544bSIlia Diachkov                CBr->getOperand(0).getReg() == CmpReg);
348*b8e1544bSIlia Diachkov         MAI.setSkipEmission(&MI);
349*b8e1544bSIlia Diachkov         MAI.setSkipEmission(CBr);
350*b8e1544bSIlia Diachkov         if (&MBB.front() == &MI && &MBB.back() == CBr)
351*b8e1544bSIlia Diachkov           MAI.MBBsToSkip.insert(&MBB);
352*b8e1544bSIlia Diachkov       }
353*b8e1544bSIlia Diachkov   }
354*b8e1544bSIlia Diachkov }
355*b8e1544bSIlia Diachkov 
356153dee34SIlia Diachkov struct SPIRV::ModuleAnalysisInfo SPIRVModuleAnalysis::MAI;
357153dee34SIlia Diachkov 
getAnalysisUsage(AnalysisUsage & AU) const358153dee34SIlia Diachkov void SPIRVModuleAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
359153dee34SIlia Diachkov   AU.addRequired<TargetPassConfig>();
360153dee34SIlia Diachkov   AU.addRequired<MachineModuleInfoWrapperPass>();
361153dee34SIlia Diachkov }
362153dee34SIlia Diachkov 
runOnModule(Module & M)363153dee34SIlia Diachkov bool SPIRVModuleAnalysis::runOnModule(Module &M) {
364153dee34SIlia Diachkov   SPIRVTargetMachine &TM =
365153dee34SIlia Diachkov       getAnalysis<TargetPassConfig>().getTM<SPIRVTargetMachine>();
366153dee34SIlia Diachkov   ST = TM.getSubtargetImpl();
367153dee34SIlia Diachkov   GR = ST->getSPIRVGlobalRegistry();
368153dee34SIlia Diachkov   TII = ST->getInstrInfo();
369153dee34SIlia Diachkov 
370153dee34SIlia Diachkov   MMI = &getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
371153dee34SIlia Diachkov 
372153dee34SIlia Diachkov   setBaseInfo(M);
373153dee34SIlia Diachkov 
374*b8e1544bSIlia Diachkov   processSwitches(M, MAI, MMI);
375*b8e1544bSIlia Diachkov 
376*b8e1544bSIlia Diachkov   // Process type/const/global var/func decl instructions, number their
377153dee34SIlia Diachkov   // destination registers from 0 to N, collect Extensions and Capabilities.
378fa2a7a25SAleksandr Bezzubikov   processDefInstrs(M);
379153dee34SIlia Diachkov 
380153dee34SIlia Diachkov   // Number rest of registers from N+1 onwards.
381153dee34SIlia Diachkov   numberRegistersGlobally(M);
382153dee34SIlia Diachkov 
383153dee34SIlia Diachkov   // Collect OpName, OpEntryPoint, OpDecorate etc, process other instructions.
384153dee34SIlia Diachkov   processOtherInstrs(M);
385153dee34SIlia Diachkov 
386153dee34SIlia Diachkov   return false;
387153dee34SIlia Diachkov }
388