1 //===- SPIRVModuleAnalysis.cpp - analysis of global instrs & regs - C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // The analysis collects instructions that should be output at the module level 10 // and performs the global register numbering. 11 // 12 // The results of this analysis are used in AsmPrinter to rename registers 13 // globally and to output required instructions at the module level. 14 // 15 //===----------------------------------------------------------------------===// 16 17 #include "SPIRVModuleAnalysis.h" 18 #include "SPIRV.h" 19 #include "SPIRVGlobalRegistry.h" 20 #include "SPIRVSubtarget.h" 21 #include "SPIRVTargetMachine.h" 22 #include "SPIRVUtils.h" 23 #include "TargetInfo/SPIRVTargetInfo.h" 24 #include "llvm/CodeGen/MachineModuleInfo.h" 25 #include "llvm/CodeGen/TargetPassConfig.h" 26 27 using namespace llvm; 28 29 #define DEBUG_TYPE "spirv-module-analysis" 30 31 char llvm::SPIRVModuleAnalysis::ID = 0; 32 33 namespace llvm { 34 void initializeSPIRVModuleAnalysisPass(PassRegistry &); 35 } // namespace llvm 36 37 INITIALIZE_PASS(SPIRVModuleAnalysis, DEBUG_TYPE, "SPIRV module analysis", true, 38 true) 39 40 // Retrieve an unsigned from an MDNode with a list of them as operands. 41 static unsigned getMetadataUInt(MDNode *MdNode, unsigned OpIndex, 42 unsigned DefaultVal = 0) { 43 if (MdNode && OpIndex < MdNode->getNumOperands()) { 44 const auto &Op = MdNode->getOperand(OpIndex); 45 return mdconst::extract<ConstantInt>(Op)->getZExtValue(); 46 } 47 return DefaultVal; 48 } 49 50 void SPIRVModuleAnalysis::setBaseInfo(const Module &M) { 51 MAI.MaxID = 0; 52 for (int i = 0; i < SPIRV::NUM_MODULE_SECTIONS; i++) 53 MAI.MS[i].clear(); 54 MAI.RegisterAliasTable.clear(); 55 MAI.InstrsToDelete.clear(); 56 MAI.FuncNameMap.clear(); 57 MAI.GlobalVarList.clear(); 58 59 // TODO: determine memory model and source language from the configuratoin. 60 MAI.Mem = SPIRV::MemoryModel::OpenCL; 61 MAI.SrcLang = SPIRV::SourceLanguage::OpenCL_C; 62 unsigned PtrSize = ST->getPointerSize(); 63 MAI.Addr = PtrSize == 32 ? SPIRV::AddressingModel::Physical32 64 : PtrSize == 64 ? SPIRV::AddressingModel::Physical64 65 : SPIRV::AddressingModel::Logical; 66 // Get the OpenCL version number from metadata. 67 // TODO: support other source languages. 68 MAI.SrcLangVersion = 0; 69 if (auto VerNode = M.getNamedMetadata("opencl.ocl.version")) { 70 // Construct version literal according to OpenCL 2.2 environment spec. 71 auto VersionMD = VerNode->getOperand(0); 72 unsigned MajorNum = getMetadataUInt(VersionMD, 0, 2); 73 unsigned MinorNum = getMetadataUInt(VersionMD, 1); 74 unsigned RevNum = getMetadataUInt(VersionMD, 2); 75 MAI.SrcLangVersion = 0 | (MajorNum << 16) | (MinorNum << 8) | RevNum; 76 } 77 } 78 79 // True if there is an instruction in the MS list with all the same operands as 80 // the given instruction has (after the given starting index). 81 // TODO: maybe it needs to check Opcodes too. 82 static bool findSameInstrInMS(const MachineInstr &A, 83 SPIRV::ModuleSectionType MSType, 84 SPIRV::ModuleAnalysisInfo &MAI, 85 bool UpdateRegAliases, 86 unsigned StartOpIndex = 0) { 87 for (const auto *B : MAI.MS[MSType]) { 88 const unsigned NumAOps = A.getNumOperands(); 89 if (NumAOps == B->getNumOperands() && A.getNumDefs() == B->getNumDefs()) { 90 bool AllOpsMatch = true; 91 for (unsigned i = StartOpIndex; i < NumAOps && AllOpsMatch; ++i) { 92 if (A.getOperand(i).isReg() && B->getOperand(i).isReg()) { 93 Register RegA = A.getOperand(i).getReg(); 94 Register RegB = B->getOperand(i).getReg(); 95 AllOpsMatch = MAI.getRegisterAlias(A.getMF(), RegA) == 96 MAI.getRegisterAlias(B->getMF(), RegB); 97 } else { 98 AllOpsMatch = A.getOperand(i).isIdenticalTo(B->getOperand(i)); 99 } 100 } 101 if (AllOpsMatch) { 102 if (UpdateRegAliases) { 103 assert(A.getOperand(0).isReg() && B->getOperand(0).isReg()); 104 Register LocalReg = A.getOperand(0).getReg(); 105 Register GlobalReg = 106 MAI.getRegisterAlias(B->getMF(), B->getOperand(0).getReg()); 107 MAI.setRegisterAlias(A.getMF(), LocalReg, GlobalReg); 108 } 109 return true; 110 } 111 } 112 } 113 return false; 114 } 115 116 // Look for IDs declared with Import linkage, and map the imported name string 117 // to the register defining that variable (which will usually be the result of 118 // an OpFunction). This lets us call externally imported functions using 119 // the correct ID registers. 120 void SPIRVModuleAnalysis::collectFuncNames(MachineInstr &MI, 121 const Function &F) { 122 if (MI.getOpcode() == SPIRV::OpDecorate) { 123 // If it's got Import linkage. 124 auto Dec = MI.getOperand(1).getImm(); 125 if (Dec == static_cast<unsigned>(SPIRV::Decoration::LinkageAttributes)) { 126 auto Lnk = MI.getOperand(MI.getNumOperands() - 1).getImm(); 127 if (Lnk == static_cast<unsigned>(SPIRV::LinkageType::Import)) { 128 // Map imported function name to function ID register. 129 std::string Name = getStringImm(MI, 2); 130 Register Target = MI.getOperand(0).getReg(); 131 // TODO: check defs from different MFs. 132 MAI.FuncNameMap[Name] = MAI.getRegisterAlias(MI.getMF(), Target); 133 } 134 } 135 } else if (MI.getOpcode() == SPIRV::OpFunction) { 136 // Record all internal OpFunction declarations. 137 Register Reg = MI.defs().begin()->getReg(); 138 Register GlobalReg = MAI.getRegisterAlias(MI.getMF(), Reg); 139 assert(GlobalReg.isValid()); 140 // TODO: check that it does not conflict with existing entries. 141 MAI.FuncNameMap[F.getGlobalIdentifier()] = GlobalReg; 142 } 143 } 144 145 // Collect the given instruction in the specified MS. We assume global register 146 // numbering has already occurred by this point. We can directly compare reg 147 // arguments when detecting duplicates. 148 static void collectOtherInstr(MachineInstr &MI, SPIRV::ModuleAnalysisInfo &MAI, 149 SPIRV::ModuleSectionType MSType, 150 bool IsConstOrType = false) { 151 MAI.setSkipEmission(&MI); 152 if (findSameInstrInMS(MI, MSType, MAI, IsConstOrType, IsConstOrType ? 1 : 0)) 153 return; // Found a duplicate, so don't add it. 154 // No duplicates, so add it. 155 MAI.MS[MSType].push_back(&MI); 156 } 157 158 // Some global instructions make reference to function-local ID regs, so cannot 159 // be correctly collected until these registers are globally numbered. 160 void SPIRVModuleAnalysis::processOtherInstrs(const Module &M) { 161 for (auto F = M.begin(), E = M.end(); F != E; ++F) { 162 if ((*F).isDeclaration()) 163 continue; 164 MachineFunction *MF = MMI->getMachineFunction(*F); 165 assert(MF); 166 unsigned FCounter = 0; 167 for (MachineBasicBlock &MBB : *MF) 168 for (MachineInstr &MI : MBB) { 169 if (MI.getOpcode() == SPIRV::OpFunction) 170 FCounter++; 171 if (MAI.getSkipEmission(&MI)) 172 continue; 173 const unsigned OpCode = MI.getOpcode(); 174 const bool IsFuncOrParm = 175 OpCode == SPIRV::OpFunction || OpCode == SPIRV::OpFunctionParameter; 176 const bool IsConstOrType = 177 TII->isConstantInstr(MI) || TII->isTypeDeclInstr(MI); 178 if (OpCode == SPIRV::OpName || OpCode == SPIRV::OpMemberName) { 179 collectOtherInstr(MI, MAI, SPIRV::MB_DebugNames); 180 } else if (OpCode == SPIRV::OpEntryPoint) { 181 collectOtherInstr(MI, MAI, SPIRV::MB_EntryPoints); 182 } else if (TII->isDecorationInstr(MI)) { 183 collectOtherInstr(MI, MAI, SPIRV::MB_Annotations); 184 collectFuncNames(MI, *F); 185 } else if (IsConstOrType || (FCounter > 1 && IsFuncOrParm)) { 186 // Now OpSpecConstant*s are not in DT, 187 // but they need to be collected anyway. 188 enum SPIRV::ModuleSectionType Type = 189 IsFuncOrParm ? SPIRV::MB_ExtFuncDecls : SPIRV::MB_TypeConstVars; 190 collectOtherInstr(MI, MAI, Type, IsConstOrType); 191 } else if (OpCode == SPIRV::OpFunction) { 192 collectFuncNames(MI, *F); 193 } 194 } 195 } 196 } 197 198 // Number registers in all functions globally from 0 onwards and store 199 // the result in global register alias table. 200 void SPIRVModuleAnalysis::numberRegistersGlobally(const Module &M) { 201 for (auto F = M.begin(), E = M.end(); F != E; ++F) { 202 if ((*F).isDeclaration()) 203 continue; 204 MachineFunction *MF = MMI->getMachineFunction(*F); 205 assert(MF); 206 for (MachineBasicBlock &MBB : *MF) { 207 for (MachineInstr &MI : MBB) { 208 for (MachineOperand &Op : MI.operands()) { 209 if (!Op.isReg()) 210 continue; 211 Register Reg = Op.getReg(); 212 if (MAI.hasRegisterAlias(MF, Reg)) 213 continue; 214 Register NewReg = Register::index2VirtReg(MAI.getNextID()); 215 MAI.setRegisterAlias(MF, Reg, NewReg); 216 } 217 } 218 } 219 } 220 } 221 222 struct SPIRV::ModuleAnalysisInfo SPIRVModuleAnalysis::MAI; 223 224 void SPIRVModuleAnalysis::getAnalysisUsage(AnalysisUsage &AU) const { 225 AU.addRequired<TargetPassConfig>(); 226 AU.addRequired<MachineModuleInfoWrapperPass>(); 227 } 228 229 bool SPIRVModuleAnalysis::runOnModule(Module &M) { 230 SPIRVTargetMachine &TM = 231 getAnalysis<TargetPassConfig>().getTM<SPIRVTargetMachine>(); 232 ST = TM.getSubtargetImpl(); 233 GR = ST->getSPIRVGlobalRegistry(); 234 TII = ST->getInstrInfo(); 235 236 MMI = &getAnalysis<MachineModuleInfoWrapperPass>().getMMI(); 237 238 setBaseInfo(M); 239 240 // TODO: Process type/const/global var/func decl instructions, number their 241 // destination registers from 0 to N, collect Extensions and Capabilities. 242 243 // Number rest of registers from N+1 onwards. 244 numberRegistersGlobally(M); 245 246 // Collect OpName, OpEntryPoint, OpDecorate etc, process other instructions. 247 processOtherInstrs(M); 248 249 return false; 250 } 251