181ad6265SDimitry Andric //===- SPIRVModuleAnalysis.cpp - analysis of global instrs & regs - C++ -*-===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric // 981ad6265SDimitry Andric // The analysis collects instructions that should be output at the module level 1081ad6265SDimitry Andric // and performs the global register numbering. 1181ad6265SDimitry Andric // 1281ad6265SDimitry Andric // The results of this analysis are used in AsmPrinter to rename registers 1381ad6265SDimitry Andric // globally and to output required instructions at the module level. 1481ad6265SDimitry Andric // 1581ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1681ad6265SDimitry Andric 1781ad6265SDimitry Andric #include "SPIRVModuleAnalysis.h" 1881ad6265SDimitry Andric #include "SPIRV.h" 1981ad6265SDimitry Andric #include "SPIRVGlobalRegistry.h" 2081ad6265SDimitry Andric #include "SPIRVSubtarget.h" 2181ad6265SDimitry Andric #include "SPIRVTargetMachine.h" 2281ad6265SDimitry Andric #include "SPIRVUtils.h" 2381ad6265SDimitry Andric #include "TargetInfo/SPIRVTargetInfo.h" 2481ad6265SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h" 2581ad6265SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 2681ad6265SDimitry Andric 2781ad6265SDimitry Andric using namespace llvm; 2881ad6265SDimitry Andric 2981ad6265SDimitry Andric #define DEBUG_TYPE "spirv-module-analysis" 3081ad6265SDimitry Andric 31753f127fSDimitry Andric static cl::opt<bool> 32753f127fSDimitry Andric SPVDumpDeps("spv-dump-deps", 33753f127fSDimitry Andric cl::desc("Dump MIR with SPIR-V dependencies info"), 34753f127fSDimitry Andric cl::Optional, cl::init(false)); 35753f127fSDimitry Andric 3681ad6265SDimitry Andric char llvm::SPIRVModuleAnalysis::ID = 0; 3781ad6265SDimitry Andric 3881ad6265SDimitry Andric namespace llvm { 3981ad6265SDimitry Andric void initializeSPIRVModuleAnalysisPass(PassRegistry &); 4081ad6265SDimitry Andric } // namespace llvm 4181ad6265SDimitry Andric 4281ad6265SDimitry Andric INITIALIZE_PASS(SPIRVModuleAnalysis, DEBUG_TYPE, "SPIRV module analysis", true, 4381ad6265SDimitry Andric true) 4481ad6265SDimitry Andric 4581ad6265SDimitry Andric // Retrieve an unsigned from an MDNode with a list of them as operands. 4681ad6265SDimitry Andric static unsigned getMetadataUInt(MDNode *MdNode, unsigned OpIndex, 4781ad6265SDimitry Andric unsigned DefaultVal = 0) { 4881ad6265SDimitry Andric if (MdNode && OpIndex < MdNode->getNumOperands()) { 4981ad6265SDimitry Andric const auto &Op = MdNode->getOperand(OpIndex); 5081ad6265SDimitry Andric return mdconst::extract<ConstantInt>(Op)->getZExtValue(); 5181ad6265SDimitry Andric } 5281ad6265SDimitry Andric return DefaultVal; 5381ad6265SDimitry Andric } 5481ad6265SDimitry Andric 5581ad6265SDimitry Andric void SPIRVModuleAnalysis::setBaseInfo(const Module &M) { 5681ad6265SDimitry Andric MAI.MaxID = 0; 5781ad6265SDimitry Andric for (int i = 0; i < SPIRV::NUM_MODULE_SECTIONS; i++) 5881ad6265SDimitry Andric MAI.MS[i].clear(); 5981ad6265SDimitry Andric MAI.RegisterAliasTable.clear(); 6081ad6265SDimitry Andric MAI.InstrsToDelete.clear(); 6181ad6265SDimitry Andric MAI.FuncNameMap.clear(); 6281ad6265SDimitry Andric MAI.GlobalVarList.clear(); 63*fcaf7f86SDimitry Andric MAI.ExtInstSetMap.clear(); 6481ad6265SDimitry Andric 6581ad6265SDimitry Andric // TODO: determine memory model and source language from the configuratoin. 66*fcaf7f86SDimitry Andric if (auto MemModel = M.getNamedMetadata("spirv.MemoryModel")) { 67*fcaf7f86SDimitry Andric auto MemMD = MemModel->getOperand(0); 68*fcaf7f86SDimitry Andric MAI.Addr = static_cast<SPIRV::AddressingModel>(getMetadataUInt(MemMD, 0)); 69*fcaf7f86SDimitry Andric MAI.Mem = static_cast<SPIRV::MemoryModel>(getMetadataUInt(MemMD, 1)); 70*fcaf7f86SDimitry Andric } else { 7181ad6265SDimitry Andric MAI.Mem = SPIRV::MemoryModel::OpenCL; 7281ad6265SDimitry Andric unsigned PtrSize = ST->getPointerSize(); 7381ad6265SDimitry Andric MAI.Addr = PtrSize == 32 ? SPIRV::AddressingModel::Physical32 7481ad6265SDimitry Andric : PtrSize == 64 ? SPIRV::AddressingModel::Physical64 7581ad6265SDimitry Andric : SPIRV::AddressingModel::Logical; 76*fcaf7f86SDimitry Andric } 7781ad6265SDimitry Andric // Get the OpenCL version number from metadata. 7881ad6265SDimitry Andric // TODO: support other source languages. 7981ad6265SDimitry Andric if (auto VerNode = M.getNamedMetadata("opencl.ocl.version")) { 80*fcaf7f86SDimitry Andric MAI.SrcLang = SPIRV::SourceLanguage::OpenCL_C; 81*fcaf7f86SDimitry Andric // Construct version literal in accordance with SPIRV-LLVM-Translator. 82*fcaf7f86SDimitry Andric // TODO: support multiple OCL version metadata. 83*fcaf7f86SDimitry Andric assert(VerNode->getNumOperands() > 0 && "Invalid SPIR"); 8481ad6265SDimitry Andric auto VersionMD = VerNode->getOperand(0); 8581ad6265SDimitry Andric unsigned MajorNum = getMetadataUInt(VersionMD, 0, 2); 8681ad6265SDimitry Andric unsigned MinorNum = getMetadataUInt(VersionMD, 1); 8781ad6265SDimitry Andric unsigned RevNum = getMetadataUInt(VersionMD, 2); 88*fcaf7f86SDimitry Andric MAI.SrcLangVersion = (MajorNum * 100 + MinorNum) * 1000 + RevNum; 89*fcaf7f86SDimitry Andric } else { 90*fcaf7f86SDimitry Andric MAI.SrcLang = SPIRV::SourceLanguage::Unknown; 91*fcaf7f86SDimitry Andric MAI.SrcLangVersion = 0; 92*fcaf7f86SDimitry Andric } 93*fcaf7f86SDimitry Andric 94*fcaf7f86SDimitry Andric if (auto ExtNode = M.getNamedMetadata("opencl.used.extensions")) { 95*fcaf7f86SDimitry Andric for (unsigned I = 0, E = ExtNode->getNumOperands(); I != E; ++I) { 96*fcaf7f86SDimitry Andric MDNode *MD = ExtNode->getOperand(I); 97*fcaf7f86SDimitry Andric if (!MD || MD->getNumOperands() == 0) 98*fcaf7f86SDimitry Andric continue; 99*fcaf7f86SDimitry Andric for (unsigned J = 0, N = MD->getNumOperands(); J != N; ++J) 100*fcaf7f86SDimitry Andric MAI.SrcExt.insert(cast<MDString>(MD->getOperand(J))->getString()); 10181ad6265SDimitry Andric } 10281ad6265SDimitry Andric } 10381ad6265SDimitry Andric 104*fcaf7f86SDimitry Andric // TODO: check if it's required by default. 105*fcaf7f86SDimitry Andric MAI.ExtInstSetMap[static_cast<unsigned>(SPIRV::InstructionSet::OpenCL_std)] = 106*fcaf7f86SDimitry Andric Register::index2VirtReg(MAI.getNextID()); 10781ad6265SDimitry Andric } 10881ad6265SDimitry Andric 109753f127fSDimitry Andric // Collect MI which defines the register in the given machine function. 110753f127fSDimitry Andric static void collectDefInstr(Register Reg, const MachineFunction *MF, 111753f127fSDimitry Andric SPIRV::ModuleAnalysisInfo *MAI, 112753f127fSDimitry Andric SPIRV::ModuleSectionType MSType, 113753f127fSDimitry Andric bool DoInsert = true) { 114753f127fSDimitry Andric assert(MAI->hasRegisterAlias(MF, Reg) && "Cannot find register alias"); 115753f127fSDimitry Andric MachineInstr *MI = MF->getRegInfo().getUniqueVRegDef(Reg); 116753f127fSDimitry Andric assert(MI && "There should be an instruction that defines the register"); 117753f127fSDimitry Andric MAI->setSkipEmission(MI); 118753f127fSDimitry Andric if (DoInsert) 119753f127fSDimitry Andric MAI->MS[MSType].push_back(MI); 120753f127fSDimitry Andric } 121753f127fSDimitry Andric 122753f127fSDimitry Andric void SPIRVModuleAnalysis::collectGlobalEntities( 123753f127fSDimitry Andric const std::vector<SPIRV::DTSortableEntry *> &DepsGraph, 124753f127fSDimitry Andric SPIRV::ModuleSectionType MSType, 125753f127fSDimitry Andric std::function<bool(const SPIRV::DTSortableEntry *)> Pred, 126*fcaf7f86SDimitry Andric bool UsePreOrder = false) { 127753f127fSDimitry Andric DenseSet<const SPIRV::DTSortableEntry *> Visited; 128753f127fSDimitry Andric for (const auto *E : DepsGraph) { 129753f127fSDimitry Andric std::function<void(const SPIRV::DTSortableEntry *)> RecHoistUtil; 130753f127fSDimitry Andric // NOTE: here we prefer recursive approach over iterative because 131753f127fSDimitry Andric // we don't expect depchains long enough to cause SO. 132753f127fSDimitry Andric RecHoistUtil = [MSType, UsePreOrder, &Visited, &Pred, 133753f127fSDimitry Andric &RecHoistUtil](const SPIRV::DTSortableEntry *E) { 134753f127fSDimitry Andric if (Visited.count(E) || !Pred(E)) 135753f127fSDimitry Andric return; 136753f127fSDimitry Andric Visited.insert(E); 137753f127fSDimitry Andric 138753f127fSDimitry Andric // Traversing deps graph in post-order allows us to get rid of 139753f127fSDimitry Andric // register aliases preprocessing. 140753f127fSDimitry Andric // But pre-order is required for correct processing of function 141753f127fSDimitry Andric // declaration and arguments processing. 142753f127fSDimitry Andric if (!UsePreOrder) 143753f127fSDimitry Andric for (auto *S : E->getDeps()) 144753f127fSDimitry Andric RecHoistUtil(S); 145753f127fSDimitry Andric 146753f127fSDimitry Andric Register GlobalReg = Register::index2VirtReg(MAI.getNextID()); 147753f127fSDimitry Andric bool IsFirst = true; 148753f127fSDimitry Andric for (auto &U : *E) { 149753f127fSDimitry Andric const MachineFunction *MF = U.first; 150753f127fSDimitry Andric Register Reg = U.second; 151753f127fSDimitry Andric MAI.setRegisterAlias(MF, Reg, GlobalReg); 152753f127fSDimitry Andric if (!MF->getRegInfo().getUniqueVRegDef(Reg)) 153753f127fSDimitry Andric continue; 154753f127fSDimitry Andric collectDefInstr(Reg, MF, &MAI, MSType, IsFirst); 155753f127fSDimitry Andric IsFirst = false; 156753f127fSDimitry Andric if (E->getIsGV()) 157753f127fSDimitry Andric MAI.GlobalVarList.push_back(MF->getRegInfo().getUniqueVRegDef(Reg)); 158753f127fSDimitry Andric } 159753f127fSDimitry Andric 160753f127fSDimitry Andric if (UsePreOrder) 161753f127fSDimitry Andric for (auto *S : E->getDeps()) 162753f127fSDimitry Andric RecHoistUtil(S); 163753f127fSDimitry Andric }; 164753f127fSDimitry Andric RecHoistUtil(E); 165753f127fSDimitry Andric } 166753f127fSDimitry Andric } 167753f127fSDimitry Andric 168753f127fSDimitry Andric // The function initializes global register alias table for types, consts, 169753f127fSDimitry Andric // global vars and func decls and collects these instruction for output 170753f127fSDimitry Andric // at module level. Also it collects explicit OpExtension/OpCapability 171753f127fSDimitry Andric // instructions. 172753f127fSDimitry Andric void SPIRVModuleAnalysis::processDefInstrs(const Module &M) { 173753f127fSDimitry Andric std::vector<SPIRV::DTSortableEntry *> DepsGraph; 174753f127fSDimitry Andric 175753f127fSDimitry Andric GR->buildDepsGraph(DepsGraph, SPVDumpDeps ? MMI : nullptr); 176753f127fSDimitry Andric 177753f127fSDimitry Andric collectGlobalEntities( 178753f127fSDimitry Andric DepsGraph, SPIRV::MB_TypeConstVars, 179*fcaf7f86SDimitry Andric [](const SPIRV::DTSortableEntry *E) { return !E->getIsFunc(); }); 180753f127fSDimitry Andric 181753f127fSDimitry Andric collectGlobalEntities( 182753f127fSDimitry Andric DepsGraph, SPIRV::MB_ExtFuncDecls, 183753f127fSDimitry Andric [](const SPIRV::DTSortableEntry *E) { return E->getIsFunc(); }, true); 184753f127fSDimitry Andric } 185753f127fSDimitry Andric 186*fcaf7f86SDimitry Andric // True if there is an instruction in the MS list with all the same operands as 187*fcaf7f86SDimitry Andric // the given instruction has (after the given starting index). 188*fcaf7f86SDimitry Andric // TODO: maybe it needs to check Opcodes too. 189*fcaf7f86SDimitry Andric static bool findSameInstrInMS(const MachineInstr &A, 190*fcaf7f86SDimitry Andric SPIRV::ModuleSectionType MSType, 191*fcaf7f86SDimitry Andric SPIRV::ModuleAnalysisInfo &MAI, 192*fcaf7f86SDimitry Andric unsigned StartOpIndex = 0) { 193*fcaf7f86SDimitry Andric for (const auto *B : MAI.MS[MSType]) { 194*fcaf7f86SDimitry Andric const unsigned NumAOps = A.getNumOperands(); 195*fcaf7f86SDimitry Andric if (NumAOps != B->getNumOperands() || A.getNumDefs() != B->getNumDefs()) 196*fcaf7f86SDimitry Andric continue; 197*fcaf7f86SDimitry Andric bool AllOpsMatch = true; 198*fcaf7f86SDimitry Andric for (unsigned i = StartOpIndex; i < NumAOps && AllOpsMatch; ++i) { 199*fcaf7f86SDimitry Andric if (A.getOperand(i).isReg() && B->getOperand(i).isReg()) { 200*fcaf7f86SDimitry Andric Register RegA = A.getOperand(i).getReg(); 201*fcaf7f86SDimitry Andric Register RegB = B->getOperand(i).getReg(); 202*fcaf7f86SDimitry Andric AllOpsMatch = MAI.getRegisterAlias(A.getMF(), RegA) == 203*fcaf7f86SDimitry Andric MAI.getRegisterAlias(B->getMF(), RegB); 204*fcaf7f86SDimitry Andric } else { 205*fcaf7f86SDimitry Andric AllOpsMatch = A.getOperand(i).isIdenticalTo(B->getOperand(i)); 206*fcaf7f86SDimitry Andric } 207*fcaf7f86SDimitry Andric } 208*fcaf7f86SDimitry Andric if (AllOpsMatch) 209*fcaf7f86SDimitry Andric return true; 210*fcaf7f86SDimitry Andric } 211*fcaf7f86SDimitry Andric return false; 212*fcaf7f86SDimitry Andric } 213*fcaf7f86SDimitry Andric 21481ad6265SDimitry Andric // Look for IDs declared with Import linkage, and map the imported name string 21581ad6265SDimitry Andric // to the register defining that variable (which will usually be the result of 21681ad6265SDimitry Andric // an OpFunction). This lets us call externally imported functions using 21781ad6265SDimitry Andric // the correct ID registers. 21881ad6265SDimitry Andric void SPIRVModuleAnalysis::collectFuncNames(MachineInstr &MI, 21981ad6265SDimitry Andric const Function &F) { 22081ad6265SDimitry Andric if (MI.getOpcode() == SPIRV::OpDecorate) { 22181ad6265SDimitry Andric // If it's got Import linkage. 22281ad6265SDimitry Andric auto Dec = MI.getOperand(1).getImm(); 22381ad6265SDimitry Andric if (Dec == static_cast<unsigned>(SPIRV::Decoration::LinkageAttributes)) { 22481ad6265SDimitry Andric auto Lnk = MI.getOperand(MI.getNumOperands() - 1).getImm(); 22581ad6265SDimitry Andric if (Lnk == static_cast<unsigned>(SPIRV::LinkageType::Import)) { 22681ad6265SDimitry Andric // Map imported function name to function ID register. 22781ad6265SDimitry Andric std::string Name = getStringImm(MI, 2); 22881ad6265SDimitry Andric Register Target = MI.getOperand(0).getReg(); 22981ad6265SDimitry Andric // TODO: check defs from different MFs. 23081ad6265SDimitry Andric MAI.FuncNameMap[Name] = MAI.getRegisterAlias(MI.getMF(), Target); 23181ad6265SDimitry Andric } 23281ad6265SDimitry Andric } 23381ad6265SDimitry Andric } else if (MI.getOpcode() == SPIRV::OpFunction) { 23481ad6265SDimitry Andric // Record all internal OpFunction declarations. 23581ad6265SDimitry Andric Register Reg = MI.defs().begin()->getReg(); 23681ad6265SDimitry Andric Register GlobalReg = MAI.getRegisterAlias(MI.getMF(), Reg); 23781ad6265SDimitry Andric assert(GlobalReg.isValid()); 23881ad6265SDimitry Andric // TODO: check that it does not conflict with existing entries. 23981ad6265SDimitry Andric MAI.FuncNameMap[F.getGlobalIdentifier()] = GlobalReg; 24081ad6265SDimitry Andric } 24181ad6265SDimitry Andric } 24281ad6265SDimitry Andric 24381ad6265SDimitry Andric // Collect the given instruction in the specified MS. We assume global register 24481ad6265SDimitry Andric // numbering has already occurred by this point. We can directly compare reg 24581ad6265SDimitry Andric // arguments when detecting duplicates. 24681ad6265SDimitry Andric static void collectOtherInstr(MachineInstr &MI, SPIRV::ModuleAnalysisInfo &MAI, 247*fcaf7f86SDimitry Andric SPIRV::ModuleSectionType MSType, 248*fcaf7f86SDimitry Andric bool Append = true) { 24981ad6265SDimitry Andric MAI.setSkipEmission(&MI); 250*fcaf7f86SDimitry Andric if (findSameInstrInMS(MI, MSType, MAI)) 25181ad6265SDimitry Andric return; // Found a duplicate, so don't add it. 25281ad6265SDimitry Andric // No duplicates, so add it. 253*fcaf7f86SDimitry Andric if (Append) 25481ad6265SDimitry Andric MAI.MS[MSType].push_back(&MI); 255*fcaf7f86SDimitry Andric else 256*fcaf7f86SDimitry Andric MAI.MS[MSType].insert(MAI.MS[MSType].begin(), &MI); 25781ad6265SDimitry Andric } 25881ad6265SDimitry Andric 25981ad6265SDimitry Andric // Some global instructions make reference to function-local ID regs, so cannot 26081ad6265SDimitry Andric // be correctly collected until these registers are globally numbered. 26181ad6265SDimitry Andric void SPIRVModuleAnalysis::processOtherInstrs(const Module &M) { 26281ad6265SDimitry Andric for (auto F = M.begin(), E = M.end(); F != E; ++F) { 26381ad6265SDimitry Andric if ((*F).isDeclaration()) 26481ad6265SDimitry Andric continue; 26581ad6265SDimitry Andric MachineFunction *MF = MMI->getMachineFunction(*F); 26681ad6265SDimitry Andric assert(MF); 26781ad6265SDimitry Andric for (MachineBasicBlock &MBB : *MF) 26881ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 26981ad6265SDimitry Andric if (MAI.getSkipEmission(&MI)) 27081ad6265SDimitry Andric continue; 27181ad6265SDimitry Andric const unsigned OpCode = MI.getOpcode(); 27281ad6265SDimitry Andric if (OpCode == SPIRV::OpName || OpCode == SPIRV::OpMemberName) { 27381ad6265SDimitry Andric collectOtherInstr(MI, MAI, SPIRV::MB_DebugNames); 27481ad6265SDimitry Andric } else if (OpCode == SPIRV::OpEntryPoint) { 27581ad6265SDimitry Andric collectOtherInstr(MI, MAI, SPIRV::MB_EntryPoints); 27681ad6265SDimitry Andric } else if (TII->isDecorationInstr(MI)) { 27781ad6265SDimitry Andric collectOtherInstr(MI, MAI, SPIRV::MB_Annotations); 27881ad6265SDimitry Andric collectFuncNames(MI, *F); 279*fcaf7f86SDimitry Andric } else if (TII->isConstantInstr(MI)) { 280*fcaf7f86SDimitry Andric // Now OpSpecConstant*s are not in DT, 281*fcaf7f86SDimitry Andric // but they need to be collected anyway. 282*fcaf7f86SDimitry Andric collectOtherInstr(MI, MAI, SPIRV::MB_TypeConstVars); 28381ad6265SDimitry Andric } else if (OpCode == SPIRV::OpFunction) { 28481ad6265SDimitry Andric collectFuncNames(MI, *F); 285*fcaf7f86SDimitry Andric } else if (OpCode == SPIRV::OpTypeForwardPointer) { 286*fcaf7f86SDimitry Andric collectOtherInstr(MI, MAI, SPIRV::MB_TypeConstVars, false); 28781ad6265SDimitry Andric } 28881ad6265SDimitry Andric } 28981ad6265SDimitry Andric } 29081ad6265SDimitry Andric } 29181ad6265SDimitry Andric 29281ad6265SDimitry Andric // Number registers in all functions globally from 0 onwards and store 293*fcaf7f86SDimitry Andric // the result in global register alias table. Some registers are already 294*fcaf7f86SDimitry Andric // numbered in collectGlobalEntities. 29581ad6265SDimitry Andric void SPIRVModuleAnalysis::numberRegistersGlobally(const Module &M) { 29681ad6265SDimitry Andric for (auto F = M.begin(), E = M.end(); F != E; ++F) { 29781ad6265SDimitry Andric if ((*F).isDeclaration()) 29881ad6265SDimitry Andric continue; 29981ad6265SDimitry Andric MachineFunction *MF = MMI->getMachineFunction(*F); 30081ad6265SDimitry Andric assert(MF); 30181ad6265SDimitry Andric for (MachineBasicBlock &MBB : *MF) { 30281ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 30381ad6265SDimitry Andric for (MachineOperand &Op : MI.operands()) { 30481ad6265SDimitry Andric if (!Op.isReg()) 30581ad6265SDimitry Andric continue; 30681ad6265SDimitry Andric Register Reg = Op.getReg(); 30781ad6265SDimitry Andric if (MAI.hasRegisterAlias(MF, Reg)) 30881ad6265SDimitry Andric continue; 30981ad6265SDimitry Andric Register NewReg = Register::index2VirtReg(MAI.getNextID()); 31081ad6265SDimitry Andric MAI.setRegisterAlias(MF, Reg, NewReg); 31181ad6265SDimitry Andric } 312*fcaf7f86SDimitry Andric if (MI.getOpcode() != SPIRV::OpExtInst) 313*fcaf7f86SDimitry Andric continue; 314*fcaf7f86SDimitry Andric auto Set = MI.getOperand(2).getImm(); 315*fcaf7f86SDimitry Andric if (MAI.ExtInstSetMap.find(Set) == MAI.ExtInstSetMap.end()) 316*fcaf7f86SDimitry Andric MAI.ExtInstSetMap[Set] = Register::index2VirtReg(MAI.getNextID()); 31781ad6265SDimitry Andric } 31881ad6265SDimitry Andric } 31981ad6265SDimitry Andric } 32081ad6265SDimitry Andric } 32181ad6265SDimitry Andric 322*fcaf7f86SDimitry Andric // Find OpIEqual and OpBranchConditional instructions originating from 323*fcaf7f86SDimitry Andric // OpSwitches, mark them skipped for emission. Also mark MBB skipped if it 324*fcaf7f86SDimitry Andric // contains only these instructions. 325*fcaf7f86SDimitry Andric static void processSwitches(const Module &M, SPIRV::ModuleAnalysisInfo &MAI, 326*fcaf7f86SDimitry Andric MachineModuleInfo *MMI) { 327*fcaf7f86SDimitry Andric DenseSet<Register> SwitchRegs; 328*fcaf7f86SDimitry Andric for (auto F = M.begin(), E = M.end(); F != E; ++F) { 329*fcaf7f86SDimitry Andric MachineFunction *MF = MMI->getMachineFunction(*F); 330*fcaf7f86SDimitry Andric if (!MF) 331*fcaf7f86SDimitry Andric continue; 332*fcaf7f86SDimitry Andric for (MachineBasicBlock &MBB : *MF) 333*fcaf7f86SDimitry Andric for (MachineInstr &MI : MBB) { 334*fcaf7f86SDimitry Andric if (MAI.getSkipEmission(&MI)) 335*fcaf7f86SDimitry Andric continue; 336*fcaf7f86SDimitry Andric if (MI.getOpcode() == SPIRV::OpSwitch) { 337*fcaf7f86SDimitry Andric assert(MI.getOperand(0).isReg()); 338*fcaf7f86SDimitry Andric SwitchRegs.insert(MI.getOperand(0).getReg()); 339*fcaf7f86SDimitry Andric } 340*fcaf7f86SDimitry Andric if (MI.getOpcode() != SPIRV::OpIEqual || !MI.getOperand(2).isReg() || 341*fcaf7f86SDimitry Andric !SwitchRegs.contains(MI.getOperand(2).getReg())) 342*fcaf7f86SDimitry Andric continue; 343*fcaf7f86SDimitry Andric Register CmpReg = MI.getOperand(0).getReg(); 344*fcaf7f86SDimitry Andric MachineInstr *CBr = MI.getNextNode(); 345*fcaf7f86SDimitry Andric assert(CBr && CBr->getOpcode() == SPIRV::OpBranchConditional && 346*fcaf7f86SDimitry Andric CBr->getOperand(0).isReg() && 347*fcaf7f86SDimitry Andric CBr->getOperand(0).getReg() == CmpReg); 348*fcaf7f86SDimitry Andric MAI.setSkipEmission(&MI); 349*fcaf7f86SDimitry Andric MAI.setSkipEmission(CBr); 350*fcaf7f86SDimitry Andric if (&MBB.front() == &MI && &MBB.back() == CBr) 351*fcaf7f86SDimitry Andric MAI.MBBsToSkip.insert(&MBB); 352*fcaf7f86SDimitry Andric } 353*fcaf7f86SDimitry Andric } 354*fcaf7f86SDimitry Andric } 355*fcaf7f86SDimitry Andric 35681ad6265SDimitry Andric struct SPIRV::ModuleAnalysisInfo SPIRVModuleAnalysis::MAI; 35781ad6265SDimitry Andric 35881ad6265SDimitry Andric void SPIRVModuleAnalysis::getAnalysisUsage(AnalysisUsage &AU) const { 35981ad6265SDimitry Andric AU.addRequired<TargetPassConfig>(); 36081ad6265SDimitry Andric AU.addRequired<MachineModuleInfoWrapperPass>(); 36181ad6265SDimitry Andric } 36281ad6265SDimitry Andric 36381ad6265SDimitry Andric bool SPIRVModuleAnalysis::runOnModule(Module &M) { 36481ad6265SDimitry Andric SPIRVTargetMachine &TM = 36581ad6265SDimitry Andric getAnalysis<TargetPassConfig>().getTM<SPIRVTargetMachine>(); 36681ad6265SDimitry Andric ST = TM.getSubtargetImpl(); 36781ad6265SDimitry Andric GR = ST->getSPIRVGlobalRegistry(); 36881ad6265SDimitry Andric TII = ST->getInstrInfo(); 36981ad6265SDimitry Andric 37081ad6265SDimitry Andric MMI = &getAnalysis<MachineModuleInfoWrapperPass>().getMMI(); 37181ad6265SDimitry Andric 37281ad6265SDimitry Andric setBaseInfo(M); 37381ad6265SDimitry Andric 374*fcaf7f86SDimitry Andric processSwitches(M, MAI, MMI); 375*fcaf7f86SDimitry Andric 376*fcaf7f86SDimitry Andric // Process type/const/global var/func decl instructions, number their 37781ad6265SDimitry Andric // destination registers from 0 to N, collect Extensions and Capabilities. 378753f127fSDimitry Andric processDefInstrs(M); 37981ad6265SDimitry Andric 38081ad6265SDimitry Andric // Number rest of registers from N+1 onwards. 38181ad6265SDimitry Andric numberRegistersGlobally(M); 38281ad6265SDimitry Andric 38381ad6265SDimitry Andric // Collect OpName, OpEntryPoint, OpDecorate etc, process other instructions. 38481ad6265SDimitry Andric processOtherInstrs(M); 38581ad6265SDimitry Andric 38681ad6265SDimitry Andric return false; 38781ad6265SDimitry Andric } 388