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" 185f757f3fSDimitry Andric #include "MCTargetDesc/SPIRVBaseInfo.h" 195f757f3fSDimitry Andric #include "MCTargetDesc/SPIRVMCTargetDesc.h" 2081ad6265SDimitry Andric #include "SPIRV.h" 2181ad6265SDimitry Andric #include "SPIRVSubtarget.h" 2281ad6265SDimitry Andric #include "SPIRVTargetMachine.h" 2381ad6265SDimitry Andric #include "SPIRVUtils.h" 2481ad6265SDimitry Andric #include "TargetInfo/SPIRVTargetInfo.h" 25bdd1243dSDimitry Andric #include "llvm/ADT/STLExtras.h" 2681ad6265SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h" 2781ad6265SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 2881ad6265SDimitry Andric 2981ad6265SDimitry Andric using namespace llvm; 3081ad6265SDimitry Andric 3181ad6265SDimitry Andric #define DEBUG_TYPE "spirv-module-analysis" 3281ad6265SDimitry Andric 33753f127fSDimitry Andric static cl::opt<bool> 34753f127fSDimitry Andric SPVDumpDeps("spv-dump-deps", 35753f127fSDimitry Andric cl::desc("Dump MIR with SPIR-V dependencies info"), 36753f127fSDimitry Andric cl::Optional, cl::init(false)); 37753f127fSDimitry Andric 3881ad6265SDimitry Andric char llvm::SPIRVModuleAnalysis::ID = 0; 3981ad6265SDimitry Andric 4081ad6265SDimitry Andric namespace llvm { 4181ad6265SDimitry Andric void initializeSPIRVModuleAnalysisPass(PassRegistry &); 4281ad6265SDimitry Andric } // namespace llvm 4381ad6265SDimitry Andric 4481ad6265SDimitry Andric INITIALIZE_PASS(SPIRVModuleAnalysis, DEBUG_TYPE, "SPIRV module analysis", true, 4581ad6265SDimitry Andric true) 4681ad6265SDimitry Andric 4781ad6265SDimitry Andric // Retrieve an unsigned from an MDNode with a list of them as operands. 4881ad6265SDimitry Andric static unsigned getMetadataUInt(MDNode *MdNode, unsigned OpIndex, 4981ad6265SDimitry Andric unsigned DefaultVal = 0) { 5081ad6265SDimitry Andric if (MdNode && OpIndex < MdNode->getNumOperands()) { 5181ad6265SDimitry Andric const auto &Op = MdNode->getOperand(OpIndex); 5281ad6265SDimitry Andric return mdconst::extract<ConstantInt>(Op)->getZExtValue(); 5381ad6265SDimitry Andric } 5481ad6265SDimitry Andric return DefaultVal; 5581ad6265SDimitry Andric } 5681ad6265SDimitry Andric 57bdd1243dSDimitry Andric static SPIRV::Requirements 58bdd1243dSDimitry Andric getSymbolicOperandRequirements(SPIRV::OperandCategory::OperandCategory Category, 59bdd1243dSDimitry Andric unsigned i, const SPIRVSubtarget &ST, 60bdd1243dSDimitry Andric SPIRV::RequirementHandler &Reqs) { 61bdd1243dSDimitry Andric unsigned ReqMinVer = getSymbolicOperandMinVersion(Category, i); 62bdd1243dSDimitry Andric unsigned ReqMaxVer = getSymbolicOperandMaxVersion(Category, i); 63bdd1243dSDimitry Andric unsigned TargetVer = ST.getSPIRVVersion(); 64bdd1243dSDimitry Andric bool MinVerOK = !ReqMinVer || !TargetVer || TargetVer >= ReqMinVer; 65bdd1243dSDimitry Andric bool MaxVerOK = !ReqMaxVer || !TargetVer || TargetVer <= ReqMaxVer; 66bdd1243dSDimitry Andric CapabilityList ReqCaps = getSymbolicOperandCapabilities(Category, i); 67bdd1243dSDimitry Andric ExtensionList ReqExts = getSymbolicOperandExtensions(Category, i); 68bdd1243dSDimitry Andric if (ReqCaps.empty()) { 69bdd1243dSDimitry Andric if (ReqExts.empty()) { 70bdd1243dSDimitry Andric if (MinVerOK && MaxVerOK) 71bdd1243dSDimitry Andric return {true, {}, {}, ReqMinVer, ReqMaxVer}; 72bdd1243dSDimitry Andric return {false, {}, {}, 0, 0}; 73bdd1243dSDimitry Andric } 74bdd1243dSDimitry Andric } else if (MinVerOK && MaxVerOK) { 75bdd1243dSDimitry Andric for (auto Cap : ReqCaps) { // Only need 1 of the capabilities to work. 76bdd1243dSDimitry Andric if (Reqs.isCapabilityAvailable(Cap)) 77bdd1243dSDimitry Andric return {true, {Cap}, {}, ReqMinVer, ReqMaxVer}; 78bdd1243dSDimitry Andric } 79bdd1243dSDimitry Andric } 80bdd1243dSDimitry Andric // If there are no capabilities, or we can't satisfy the version or 81bdd1243dSDimitry Andric // capability requirements, use the list of extensions (if the subtarget 82bdd1243dSDimitry Andric // can handle them all). 83bdd1243dSDimitry Andric if (llvm::all_of(ReqExts, [&ST](const SPIRV::Extension::Extension &Ext) { 84bdd1243dSDimitry Andric return ST.canUseExtension(Ext); 85bdd1243dSDimitry Andric })) { 86bdd1243dSDimitry Andric return {true, {}, ReqExts, 0, 0}; // TODO: add versions to extensions. 87bdd1243dSDimitry Andric } 88bdd1243dSDimitry Andric return {false, {}, {}, 0, 0}; 89bdd1243dSDimitry Andric } 90bdd1243dSDimitry Andric 9181ad6265SDimitry Andric void SPIRVModuleAnalysis::setBaseInfo(const Module &M) { 9281ad6265SDimitry Andric MAI.MaxID = 0; 9381ad6265SDimitry Andric for (int i = 0; i < SPIRV::NUM_MODULE_SECTIONS; i++) 9481ad6265SDimitry Andric MAI.MS[i].clear(); 9581ad6265SDimitry Andric MAI.RegisterAliasTable.clear(); 9681ad6265SDimitry Andric MAI.InstrsToDelete.clear(); 97bdd1243dSDimitry Andric MAI.FuncMap.clear(); 9881ad6265SDimitry Andric MAI.GlobalVarList.clear(); 99fcaf7f86SDimitry Andric MAI.ExtInstSetMap.clear(); 100bdd1243dSDimitry Andric MAI.Reqs.clear(); 101bdd1243dSDimitry Andric MAI.Reqs.initAvailableCapabilities(*ST); 10281ad6265SDimitry Andric 10381ad6265SDimitry Andric // TODO: determine memory model and source language from the configuratoin. 104fcaf7f86SDimitry Andric if (auto MemModel = M.getNamedMetadata("spirv.MemoryModel")) { 105fcaf7f86SDimitry Andric auto MemMD = MemModel->getOperand(0); 106bdd1243dSDimitry Andric MAI.Addr = static_cast<SPIRV::AddressingModel::AddressingModel>( 107bdd1243dSDimitry Andric getMetadataUInt(MemMD, 0)); 108bdd1243dSDimitry Andric MAI.Mem = 109bdd1243dSDimitry Andric static_cast<SPIRV::MemoryModel::MemoryModel>(getMetadataUInt(MemMD, 1)); 110fcaf7f86SDimitry Andric } else { 1115f757f3fSDimitry Andric // TODO: Add support for VulkanMemoryModel. 1125f757f3fSDimitry Andric MAI.Mem = ST->isOpenCLEnv() ? SPIRV::MemoryModel::OpenCL 1135f757f3fSDimitry Andric : SPIRV::MemoryModel::GLSL450; 1145f757f3fSDimitry Andric if (MAI.Mem == SPIRV::MemoryModel::OpenCL) { 11581ad6265SDimitry Andric unsigned PtrSize = ST->getPointerSize(); 11681ad6265SDimitry Andric MAI.Addr = PtrSize == 32 ? SPIRV::AddressingModel::Physical32 11781ad6265SDimitry Andric : PtrSize == 64 ? SPIRV::AddressingModel::Physical64 11881ad6265SDimitry Andric : SPIRV::AddressingModel::Logical; 1195f757f3fSDimitry Andric } else { 1205f757f3fSDimitry Andric // TODO: Add support for PhysicalStorageBufferAddress. 1215f757f3fSDimitry Andric MAI.Addr = SPIRV::AddressingModel::Logical; 1225f757f3fSDimitry Andric } 123fcaf7f86SDimitry Andric } 12481ad6265SDimitry Andric // Get the OpenCL version number from metadata. 12581ad6265SDimitry Andric // TODO: support other source languages. 12681ad6265SDimitry Andric if (auto VerNode = M.getNamedMetadata("opencl.ocl.version")) { 127fcaf7f86SDimitry Andric MAI.SrcLang = SPIRV::SourceLanguage::OpenCL_C; 128fcaf7f86SDimitry Andric // Construct version literal in accordance with SPIRV-LLVM-Translator. 129fcaf7f86SDimitry Andric // TODO: support multiple OCL version metadata. 130fcaf7f86SDimitry Andric assert(VerNode->getNumOperands() > 0 && "Invalid SPIR"); 13181ad6265SDimitry Andric auto VersionMD = VerNode->getOperand(0); 13281ad6265SDimitry Andric unsigned MajorNum = getMetadataUInt(VersionMD, 0, 2); 13381ad6265SDimitry Andric unsigned MinorNum = getMetadataUInt(VersionMD, 1); 13481ad6265SDimitry Andric unsigned RevNum = getMetadataUInt(VersionMD, 2); 135fcaf7f86SDimitry Andric MAI.SrcLangVersion = (MajorNum * 100 + MinorNum) * 1000 + RevNum; 136fcaf7f86SDimitry Andric } else { 137fcaf7f86SDimitry Andric MAI.SrcLang = SPIRV::SourceLanguage::Unknown; 138fcaf7f86SDimitry Andric MAI.SrcLangVersion = 0; 139fcaf7f86SDimitry Andric } 140fcaf7f86SDimitry Andric 141fcaf7f86SDimitry Andric if (auto ExtNode = M.getNamedMetadata("opencl.used.extensions")) { 142fcaf7f86SDimitry Andric for (unsigned I = 0, E = ExtNode->getNumOperands(); I != E; ++I) { 143fcaf7f86SDimitry Andric MDNode *MD = ExtNode->getOperand(I); 144fcaf7f86SDimitry Andric if (!MD || MD->getNumOperands() == 0) 145fcaf7f86SDimitry Andric continue; 146fcaf7f86SDimitry Andric for (unsigned J = 0, N = MD->getNumOperands(); J != N; ++J) 147fcaf7f86SDimitry Andric MAI.SrcExt.insert(cast<MDString>(MD->getOperand(J))->getString()); 14881ad6265SDimitry Andric } 14981ad6265SDimitry Andric } 15081ad6265SDimitry Andric 151bdd1243dSDimitry Andric // Update required capabilities for this memory model, addressing model and 152bdd1243dSDimitry Andric // source language. 153bdd1243dSDimitry Andric MAI.Reqs.getAndAddRequirements(SPIRV::OperandCategory::MemoryModelOperand, 154bdd1243dSDimitry Andric MAI.Mem, *ST); 155bdd1243dSDimitry Andric MAI.Reqs.getAndAddRequirements(SPIRV::OperandCategory::SourceLanguageOperand, 156bdd1243dSDimitry Andric MAI.SrcLang, *ST); 157bdd1243dSDimitry Andric MAI.Reqs.getAndAddRequirements(SPIRV::OperandCategory::AddressingModelOperand, 158bdd1243dSDimitry Andric MAI.Addr, *ST); 159bdd1243dSDimitry Andric 1605f757f3fSDimitry Andric if (ST->isOpenCLEnv()) { 161fcaf7f86SDimitry Andric // TODO: check if it's required by default. 1625f757f3fSDimitry Andric MAI.ExtInstSetMap[static_cast<unsigned>( 1635f757f3fSDimitry Andric SPIRV::InstructionSet::OpenCL_std)] = 164fcaf7f86SDimitry Andric Register::index2VirtReg(MAI.getNextID()); 16581ad6265SDimitry Andric } 1665f757f3fSDimitry Andric } 16781ad6265SDimitry Andric 168753f127fSDimitry Andric // Collect MI which defines the register in the given machine function. 169753f127fSDimitry Andric static void collectDefInstr(Register Reg, const MachineFunction *MF, 170753f127fSDimitry Andric SPIRV::ModuleAnalysisInfo *MAI, 171753f127fSDimitry Andric SPIRV::ModuleSectionType MSType, 172753f127fSDimitry Andric bool DoInsert = true) { 173753f127fSDimitry Andric assert(MAI->hasRegisterAlias(MF, Reg) && "Cannot find register alias"); 174753f127fSDimitry Andric MachineInstr *MI = MF->getRegInfo().getUniqueVRegDef(Reg); 175753f127fSDimitry Andric assert(MI && "There should be an instruction that defines the register"); 176753f127fSDimitry Andric MAI->setSkipEmission(MI); 177753f127fSDimitry Andric if (DoInsert) 178753f127fSDimitry Andric MAI->MS[MSType].push_back(MI); 179753f127fSDimitry Andric } 180753f127fSDimitry Andric 181753f127fSDimitry Andric void SPIRVModuleAnalysis::collectGlobalEntities( 182753f127fSDimitry Andric const std::vector<SPIRV::DTSortableEntry *> &DepsGraph, 183753f127fSDimitry Andric SPIRV::ModuleSectionType MSType, 184753f127fSDimitry Andric std::function<bool(const SPIRV::DTSortableEntry *)> Pred, 185fcaf7f86SDimitry Andric bool UsePreOrder = false) { 186753f127fSDimitry Andric DenseSet<const SPIRV::DTSortableEntry *> Visited; 187753f127fSDimitry Andric for (const auto *E : DepsGraph) { 188753f127fSDimitry Andric std::function<void(const SPIRV::DTSortableEntry *)> RecHoistUtil; 189753f127fSDimitry Andric // NOTE: here we prefer recursive approach over iterative because 190753f127fSDimitry Andric // we don't expect depchains long enough to cause SO. 191753f127fSDimitry Andric RecHoistUtil = [MSType, UsePreOrder, &Visited, &Pred, 192753f127fSDimitry Andric &RecHoistUtil](const SPIRV::DTSortableEntry *E) { 193753f127fSDimitry Andric if (Visited.count(E) || !Pred(E)) 194753f127fSDimitry Andric return; 195753f127fSDimitry Andric Visited.insert(E); 196753f127fSDimitry Andric 197753f127fSDimitry Andric // Traversing deps graph in post-order allows us to get rid of 198753f127fSDimitry Andric // register aliases preprocessing. 199753f127fSDimitry Andric // But pre-order is required for correct processing of function 200753f127fSDimitry Andric // declaration and arguments processing. 201753f127fSDimitry Andric if (!UsePreOrder) 202753f127fSDimitry Andric for (auto *S : E->getDeps()) 203753f127fSDimitry Andric RecHoistUtil(S); 204753f127fSDimitry Andric 205753f127fSDimitry Andric Register GlobalReg = Register::index2VirtReg(MAI.getNextID()); 206753f127fSDimitry Andric bool IsFirst = true; 207753f127fSDimitry Andric for (auto &U : *E) { 208753f127fSDimitry Andric const MachineFunction *MF = U.first; 209753f127fSDimitry Andric Register Reg = U.second; 210753f127fSDimitry Andric MAI.setRegisterAlias(MF, Reg, GlobalReg); 211753f127fSDimitry Andric if (!MF->getRegInfo().getUniqueVRegDef(Reg)) 212753f127fSDimitry Andric continue; 213753f127fSDimitry Andric collectDefInstr(Reg, MF, &MAI, MSType, IsFirst); 214753f127fSDimitry Andric IsFirst = false; 215753f127fSDimitry Andric if (E->getIsGV()) 216753f127fSDimitry Andric MAI.GlobalVarList.push_back(MF->getRegInfo().getUniqueVRegDef(Reg)); 217753f127fSDimitry Andric } 218753f127fSDimitry Andric 219753f127fSDimitry Andric if (UsePreOrder) 220753f127fSDimitry Andric for (auto *S : E->getDeps()) 221753f127fSDimitry Andric RecHoistUtil(S); 222753f127fSDimitry Andric }; 223753f127fSDimitry Andric RecHoistUtil(E); 224753f127fSDimitry Andric } 225753f127fSDimitry Andric } 226753f127fSDimitry Andric 227753f127fSDimitry Andric // The function initializes global register alias table for types, consts, 228753f127fSDimitry Andric // global vars and func decls and collects these instruction for output 229753f127fSDimitry Andric // at module level. Also it collects explicit OpExtension/OpCapability 230753f127fSDimitry Andric // instructions. 231753f127fSDimitry Andric void SPIRVModuleAnalysis::processDefInstrs(const Module &M) { 232753f127fSDimitry Andric std::vector<SPIRV::DTSortableEntry *> DepsGraph; 233753f127fSDimitry Andric 234753f127fSDimitry Andric GR->buildDepsGraph(DepsGraph, SPVDumpDeps ? MMI : nullptr); 235753f127fSDimitry Andric 236753f127fSDimitry Andric collectGlobalEntities( 237753f127fSDimitry Andric DepsGraph, SPIRV::MB_TypeConstVars, 238fcaf7f86SDimitry Andric [](const SPIRV::DTSortableEntry *E) { return !E->getIsFunc(); }); 239753f127fSDimitry Andric 240bdd1243dSDimitry Andric for (auto F = M.begin(), E = M.end(); F != E; ++F) { 241bdd1243dSDimitry Andric MachineFunction *MF = MMI->getMachineFunction(*F); 242bdd1243dSDimitry Andric if (!MF) 243bdd1243dSDimitry Andric continue; 244bdd1243dSDimitry Andric // Iterate through and collect OpExtension/OpCapability instructions. 245bdd1243dSDimitry Andric for (MachineBasicBlock &MBB : *MF) { 246bdd1243dSDimitry Andric for (MachineInstr &MI : MBB) { 247bdd1243dSDimitry Andric if (MI.getOpcode() == SPIRV::OpExtension) { 248bdd1243dSDimitry Andric // Here, OpExtension just has a single enum operand, not a string. 249bdd1243dSDimitry Andric auto Ext = SPIRV::Extension::Extension(MI.getOperand(0).getImm()); 250bdd1243dSDimitry Andric MAI.Reqs.addExtension(Ext); 251bdd1243dSDimitry Andric MAI.setSkipEmission(&MI); 252bdd1243dSDimitry Andric } else if (MI.getOpcode() == SPIRV::OpCapability) { 253bdd1243dSDimitry Andric auto Cap = SPIRV::Capability::Capability(MI.getOperand(0).getImm()); 254bdd1243dSDimitry Andric MAI.Reqs.addCapability(Cap); 255bdd1243dSDimitry Andric MAI.setSkipEmission(&MI); 256bdd1243dSDimitry Andric } 257bdd1243dSDimitry Andric } 258bdd1243dSDimitry Andric } 259bdd1243dSDimitry Andric } 260bdd1243dSDimitry Andric 261753f127fSDimitry Andric collectGlobalEntities( 262753f127fSDimitry Andric DepsGraph, SPIRV::MB_ExtFuncDecls, 263753f127fSDimitry Andric [](const SPIRV::DTSortableEntry *E) { return E->getIsFunc(); }, true); 264753f127fSDimitry Andric } 265753f127fSDimitry Andric 266bdd1243dSDimitry Andric // Look for IDs declared with Import linkage, and map the corresponding function 26781ad6265SDimitry Andric // to the register defining that variable (which will usually be the result of 26881ad6265SDimitry Andric // an OpFunction). This lets us call externally imported functions using 26981ad6265SDimitry Andric // the correct ID registers. 27081ad6265SDimitry Andric void SPIRVModuleAnalysis::collectFuncNames(MachineInstr &MI, 271bdd1243dSDimitry Andric const Function *F) { 27281ad6265SDimitry Andric if (MI.getOpcode() == SPIRV::OpDecorate) { 27381ad6265SDimitry Andric // If it's got Import linkage. 27481ad6265SDimitry Andric auto Dec = MI.getOperand(1).getImm(); 27581ad6265SDimitry Andric if (Dec == static_cast<unsigned>(SPIRV::Decoration::LinkageAttributes)) { 27681ad6265SDimitry Andric auto Lnk = MI.getOperand(MI.getNumOperands() - 1).getImm(); 27781ad6265SDimitry Andric if (Lnk == static_cast<unsigned>(SPIRV::LinkageType::Import)) { 27881ad6265SDimitry Andric // Map imported function name to function ID register. 279bdd1243dSDimitry Andric const Function *ImportedFunc = 280bdd1243dSDimitry Andric F->getParent()->getFunction(getStringImm(MI, 2)); 28181ad6265SDimitry Andric Register Target = MI.getOperand(0).getReg(); 282bdd1243dSDimitry Andric MAI.FuncMap[ImportedFunc] = MAI.getRegisterAlias(MI.getMF(), Target); 28381ad6265SDimitry Andric } 28481ad6265SDimitry Andric } 28581ad6265SDimitry Andric } else if (MI.getOpcode() == SPIRV::OpFunction) { 28681ad6265SDimitry Andric // Record all internal OpFunction declarations. 28781ad6265SDimitry Andric Register Reg = MI.defs().begin()->getReg(); 28881ad6265SDimitry Andric Register GlobalReg = MAI.getRegisterAlias(MI.getMF(), Reg); 28981ad6265SDimitry Andric assert(GlobalReg.isValid()); 290bdd1243dSDimitry Andric MAI.FuncMap[F] = GlobalReg; 29181ad6265SDimitry Andric } 29281ad6265SDimitry Andric } 29381ad6265SDimitry Andric 294*7a6dacacSDimitry Andric using InstrSignature = SmallVector<size_t>; 295*7a6dacacSDimitry Andric using InstrTraces = std::set<InstrSignature>; 296*7a6dacacSDimitry Andric 297*7a6dacacSDimitry Andric // Returns a representation of an instruction as a vector of MachineOperand 298*7a6dacacSDimitry Andric // hash values, see llvm::hash_value(const MachineOperand &MO) for details. 299*7a6dacacSDimitry Andric // This creates a signature of the instruction with the same content 300*7a6dacacSDimitry Andric // that MachineOperand::isIdenticalTo uses for comparison. 301*7a6dacacSDimitry Andric static InstrSignature instrToSignature(MachineInstr &MI, 302*7a6dacacSDimitry Andric SPIRV::ModuleAnalysisInfo &MAI) { 303*7a6dacacSDimitry Andric InstrSignature Signature; 304*7a6dacacSDimitry Andric for (unsigned i = 0; i < MI.getNumOperands(); ++i) { 305*7a6dacacSDimitry Andric const MachineOperand &MO = MI.getOperand(i); 306*7a6dacacSDimitry Andric size_t h; 307*7a6dacacSDimitry Andric if (MO.isReg()) { 308*7a6dacacSDimitry Andric Register RegAlias = MAI.getRegisterAlias(MI.getMF(), MO.getReg()); 309*7a6dacacSDimitry Andric // mimic llvm::hash_value(const MachineOperand &MO) 310*7a6dacacSDimitry Andric h = hash_combine(MO.getType(), (unsigned)RegAlias, MO.getSubReg(), 311*7a6dacacSDimitry Andric MO.isDef()); 312*7a6dacacSDimitry Andric } else { 313*7a6dacacSDimitry Andric h = hash_value(MO); 314*7a6dacacSDimitry Andric } 315*7a6dacacSDimitry Andric Signature.push_back(h); 316*7a6dacacSDimitry Andric } 317*7a6dacacSDimitry Andric return Signature; 318*7a6dacacSDimitry Andric } 319*7a6dacacSDimitry Andric 32081ad6265SDimitry Andric // Collect the given instruction in the specified MS. We assume global register 32181ad6265SDimitry Andric // numbering has already occurred by this point. We can directly compare reg 32281ad6265SDimitry Andric // arguments when detecting duplicates. 32381ad6265SDimitry Andric static void collectOtherInstr(MachineInstr &MI, SPIRV::ModuleAnalysisInfo &MAI, 324*7a6dacacSDimitry Andric SPIRV::ModuleSectionType MSType, InstrTraces &IS, 325fcaf7f86SDimitry Andric bool Append = true) { 32681ad6265SDimitry Andric MAI.setSkipEmission(&MI); 327*7a6dacacSDimitry Andric InstrSignature MISign = instrToSignature(MI, MAI); 328*7a6dacacSDimitry Andric auto FoundMI = IS.insert(MISign); 329*7a6dacacSDimitry Andric if (!FoundMI.second) 330*7a6dacacSDimitry Andric return; // insert failed, so we found a duplicate; don't add it to MAI.MS 33181ad6265SDimitry Andric // No duplicates, so add it. 332fcaf7f86SDimitry Andric if (Append) 33381ad6265SDimitry Andric MAI.MS[MSType].push_back(&MI); 334fcaf7f86SDimitry Andric else 335fcaf7f86SDimitry Andric MAI.MS[MSType].insert(MAI.MS[MSType].begin(), &MI); 33681ad6265SDimitry Andric } 33781ad6265SDimitry Andric 33881ad6265SDimitry Andric // Some global instructions make reference to function-local ID regs, so cannot 33981ad6265SDimitry Andric // be correctly collected until these registers are globally numbered. 34081ad6265SDimitry Andric void SPIRVModuleAnalysis::processOtherInstrs(const Module &M) { 341*7a6dacacSDimitry Andric InstrTraces IS; 34281ad6265SDimitry Andric for (auto F = M.begin(), E = M.end(); F != E; ++F) { 34381ad6265SDimitry Andric if ((*F).isDeclaration()) 34481ad6265SDimitry Andric continue; 34581ad6265SDimitry Andric MachineFunction *MF = MMI->getMachineFunction(*F); 34681ad6265SDimitry Andric assert(MF); 34781ad6265SDimitry Andric for (MachineBasicBlock &MBB : *MF) 34881ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 34981ad6265SDimitry Andric if (MAI.getSkipEmission(&MI)) 35081ad6265SDimitry Andric continue; 35181ad6265SDimitry Andric const unsigned OpCode = MI.getOpcode(); 35281ad6265SDimitry Andric if (OpCode == SPIRV::OpName || OpCode == SPIRV::OpMemberName) { 353*7a6dacacSDimitry Andric collectOtherInstr(MI, MAI, SPIRV::MB_DebugNames, IS); 35481ad6265SDimitry Andric } else if (OpCode == SPIRV::OpEntryPoint) { 355*7a6dacacSDimitry Andric collectOtherInstr(MI, MAI, SPIRV::MB_EntryPoints, IS); 35681ad6265SDimitry Andric } else if (TII->isDecorationInstr(MI)) { 357*7a6dacacSDimitry Andric collectOtherInstr(MI, MAI, SPIRV::MB_Annotations, IS); 358bdd1243dSDimitry Andric collectFuncNames(MI, &*F); 359fcaf7f86SDimitry Andric } else if (TII->isConstantInstr(MI)) { 360fcaf7f86SDimitry Andric // Now OpSpecConstant*s are not in DT, 361fcaf7f86SDimitry Andric // but they need to be collected anyway. 362*7a6dacacSDimitry Andric collectOtherInstr(MI, MAI, SPIRV::MB_TypeConstVars, IS); 36381ad6265SDimitry Andric } else if (OpCode == SPIRV::OpFunction) { 364bdd1243dSDimitry Andric collectFuncNames(MI, &*F); 365fcaf7f86SDimitry Andric } else if (OpCode == SPIRV::OpTypeForwardPointer) { 366*7a6dacacSDimitry Andric collectOtherInstr(MI, MAI, SPIRV::MB_TypeConstVars, IS, false); 36781ad6265SDimitry Andric } 36881ad6265SDimitry Andric } 36981ad6265SDimitry Andric } 37081ad6265SDimitry Andric } 37181ad6265SDimitry Andric 37281ad6265SDimitry Andric // Number registers in all functions globally from 0 onwards and store 373fcaf7f86SDimitry Andric // the result in global register alias table. Some registers are already 374fcaf7f86SDimitry Andric // numbered in collectGlobalEntities. 37581ad6265SDimitry Andric void SPIRVModuleAnalysis::numberRegistersGlobally(const Module &M) { 37681ad6265SDimitry Andric for (auto F = M.begin(), E = M.end(); F != E; ++F) { 37781ad6265SDimitry Andric if ((*F).isDeclaration()) 37881ad6265SDimitry Andric continue; 37981ad6265SDimitry Andric MachineFunction *MF = MMI->getMachineFunction(*F); 38081ad6265SDimitry Andric assert(MF); 38181ad6265SDimitry Andric for (MachineBasicBlock &MBB : *MF) { 38281ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 38381ad6265SDimitry Andric for (MachineOperand &Op : MI.operands()) { 38481ad6265SDimitry Andric if (!Op.isReg()) 38581ad6265SDimitry Andric continue; 38681ad6265SDimitry Andric Register Reg = Op.getReg(); 38781ad6265SDimitry Andric if (MAI.hasRegisterAlias(MF, Reg)) 38881ad6265SDimitry Andric continue; 38981ad6265SDimitry Andric Register NewReg = Register::index2VirtReg(MAI.getNextID()); 39081ad6265SDimitry Andric MAI.setRegisterAlias(MF, Reg, NewReg); 39181ad6265SDimitry Andric } 392fcaf7f86SDimitry Andric if (MI.getOpcode() != SPIRV::OpExtInst) 393fcaf7f86SDimitry Andric continue; 394fcaf7f86SDimitry Andric auto Set = MI.getOperand(2).getImm(); 395cb14a3feSDimitry Andric if (!MAI.ExtInstSetMap.contains(Set)) 396fcaf7f86SDimitry Andric MAI.ExtInstSetMap[Set] = Register::index2VirtReg(MAI.getNextID()); 39781ad6265SDimitry Andric } 39881ad6265SDimitry Andric } 39981ad6265SDimitry Andric } 40081ad6265SDimitry Andric } 40181ad6265SDimitry Andric 402bdd1243dSDimitry Andric // RequirementHandler implementations. 403bdd1243dSDimitry Andric void SPIRV::RequirementHandler::getAndAddRequirements( 404bdd1243dSDimitry Andric SPIRV::OperandCategory::OperandCategory Category, uint32_t i, 405bdd1243dSDimitry Andric const SPIRVSubtarget &ST) { 406bdd1243dSDimitry Andric addRequirements(getSymbolicOperandRequirements(Category, i, ST, *this)); 407bdd1243dSDimitry Andric } 408bdd1243dSDimitry Andric 409bdd1243dSDimitry Andric void SPIRV::RequirementHandler::pruneCapabilities( 410bdd1243dSDimitry Andric const CapabilityList &ToPrune) { 411bdd1243dSDimitry Andric for (const auto &Cap : ToPrune) { 412bdd1243dSDimitry Andric AllCaps.insert(Cap); 413*7a6dacacSDimitry Andric auto FoundIndex = llvm::find(MinimalCaps, Cap); 414bdd1243dSDimitry Andric if (FoundIndex != MinimalCaps.end()) 415bdd1243dSDimitry Andric MinimalCaps.erase(FoundIndex); 416bdd1243dSDimitry Andric CapabilityList ImplicitDecls = 417bdd1243dSDimitry Andric getSymbolicOperandCapabilities(OperandCategory::CapabilityOperand, Cap); 418bdd1243dSDimitry Andric pruneCapabilities(ImplicitDecls); 419bdd1243dSDimitry Andric } 420bdd1243dSDimitry Andric } 421bdd1243dSDimitry Andric 422bdd1243dSDimitry Andric void SPIRV::RequirementHandler::addCapabilities(const CapabilityList &ToAdd) { 423bdd1243dSDimitry Andric for (const auto &Cap : ToAdd) { 424bdd1243dSDimitry Andric bool IsNewlyInserted = AllCaps.insert(Cap).second; 425bdd1243dSDimitry Andric if (!IsNewlyInserted) // Don't re-add if it's already been declared. 426bdd1243dSDimitry Andric continue; 427bdd1243dSDimitry Andric CapabilityList ImplicitDecls = 428bdd1243dSDimitry Andric getSymbolicOperandCapabilities(OperandCategory::CapabilityOperand, Cap); 429bdd1243dSDimitry Andric pruneCapabilities(ImplicitDecls); 430bdd1243dSDimitry Andric MinimalCaps.push_back(Cap); 431bdd1243dSDimitry Andric } 432bdd1243dSDimitry Andric } 433bdd1243dSDimitry Andric 434bdd1243dSDimitry Andric void SPIRV::RequirementHandler::addRequirements( 435bdd1243dSDimitry Andric const SPIRV::Requirements &Req) { 436bdd1243dSDimitry Andric if (!Req.IsSatisfiable) 437bdd1243dSDimitry Andric report_fatal_error("Adding SPIR-V requirements this target can't satisfy."); 438bdd1243dSDimitry Andric 439bdd1243dSDimitry Andric if (Req.Cap.has_value()) 440bdd1243dSDimitry Andric addCapabilities({Req.Cap.value()}); 441bdd1243dSDimitry Andric 442bdd1243dSDimitry Andric addExtensions(Req.Exts); 443bdd1243dSDimitry Andric 444bdd1243dSDimitry Andric if (Req.MinVer) { 445bdd1243dSDimitry Andric if (MaxVersion && Req.MinVer > MaxVersion) { 446bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Conflicting version requirements: >= " << Req.MinVer 447bdd1243dSDimitry Andric << " and <= " << MaxVersion << "\n"); 448bdd1243dSDimitry Andric report_fatal_error("Adding SPIR-V requirements that can't be satisfied."); 449bdd1243dSDimitry Andric } 450bdd1243dSDimitry Andric 451bdd1243dSDimitry Andric if (MinVersion == 0 || Req.MinVer > MinVersion) 452bdd1243dSDimitry Andric MinVersion = Req.MinVer; 453bdd1243dSDimitry Andric } 454bdd1243dSDimitry Andric 455bdd1243dSDimitry Andric if (Req.MaxVer) { 456bdd1243dSDimitry Andric if (MinVersion && Req.MaxVer < MinVersion) { 457bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Conflicting version requirements: <= " << Req.MaxVer 458bdd1243dSDimitry Andric << " and >= " << MinVersion << "\n"); 459bdd1243dSDimitry Andric report_fatal_error("Adding SPIR-V requirements that can't be satisfied."); 460bdd1243dSDimitry Andric } 461bdd1243dSDimitry Andric 462bdd1243dSDimitry Andric if (MaxVersion == 0 || Req.MaxVer < MaxVersion) 463bdd1243dSDimitry Andric MaxVersion = Req.MaxVer; 464bdd1243dSDimitry Andric } 465bdd1243dSDimitry Andric } 466bdd1243dSDimitry Andric 467bdd1243dSDimitry Andric void SPIRV::RequirementHandler::checkSatisfiable( 468bdd1243dSDimitry Andric const SPIRVSubtarget &ST) const { 469bdd1243dSDimitry Andric // Report as many errors as possible before aborting the compilation. 470bdd1243dSDimitry Andric bool IsSatisfiable = true; 471bdd1243dSDimitry Andric auto TargetVer = ST.getSPIRVVersion(); 472bdd1243dSDimitry Andric 473bdd1243dSDimitry Andric if (MaxVersion && TargetVer && MaxVersion < TargetVer) { 474bdd1243dSDimitry Andric LLVM_DEBUG( 475bdd1243dSDimitry Andric dbgs() << "Target SPIR-V version too high for required features\n" 476bdd1243dSDimitry Andric << "Required max version: " << MaxVersion << " target version " 477bdd1243dSDimitry Andric << TargetVer << "\n"); 478bdd1243dSDimitry Andric IsSatisfiable = false; 479bdd1243dSDimitry Andric } 480bdd1243dSDimitry Andric 481bdd1243dSDimitry Andric if (MinVersion && TargetVer && MinVersion > TargetVer) { 482bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Target SPIR-V version too low for required features\n" 483bdd1243dSDimitry Andric << "Required min version: " << MinVersion 484bdd1243dSDimitry Andric << " target version " << TargetVer << "\n"); 485bdd1243dSDimitry Andric IsSatisfiable = false; 486bdd1243dSDimitry Andric } 487bdd1243dSDimitry Andric 488bdd1243dSDimitry Andric if (MinVersion && MaxVersion && MinVersion > MaxVersion) { 489bdd1243dSDimitry Andric LLVM_DEBUG( 490bdd1243dSDimitry Andric dbgs() 491bdd1243dSDimitry Andric << "Version is too low for some features and too high for others.\n" 492bdd1243dSDimitry Andric << "Required SPIR-V min version: " << MinVersion 493bdd1243dSDimitry Andric << " required SPIR-V max version " << MaxVersion << "\n"); 494bdd1243dSDimitry Andric IsSatisfiable = false; 495bdd1243dSDimitry Andric } 496bdd1243dSDimitry Andric 497bdd1243dSDimitry Andric for (auto Cap : MinimalCaps) { 498bdd1243dSDimitry Andric if (AvailableCaps.contains(Cap)) 499bdd1243dSDimitry Andric continue; 500bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Capability not supported: " 501bdd1243dSDimitry Andric << getSymbolicOperandMnemonic( 502bdd1243dSDimitry Andric OperandCategory::CapabilityOperand, Cap) 503bdd1243dSDimitry Andric << "\n"); 504bdd1243dSDimitry Andric IsSatisfiable = false; 505bdd1243dSDimitry Andric } 506bdd1243dSDimitry Andric 507bdd1243dSDimitry Andric for (auto Ext : AllExtensions) { 508bdd1243dSDimitry Andric if (ST.canUseExtension(Ext)) 509bdd1243dSDimitry Andric continue; 5105f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Extension not supported: " 511bdd1243dSDimitry Andric << getSymbolicOperandMnemonic( 512bdd1243dSDimitry Andric OperandCategory::ExtensionOperand, Ext) 513bdd1243dSDimitry Andric << "\n"); 514bdd1243dSDimitry Andric IsSatisfiable = false; 515bdd1243dSDimitry Andric } 516bdd1243dSDimitry Andric 517bdd1243dSDimitry Andric if (!IsSatisfiable) 518bdd1243dSDimitry Andric report_fatal_error("Unable to meet SPIR-V requirements for this target."); 519bdd1243dSDimitry Andric } 520bdd1243dSDimitry Andric 521bdd1243dSDimitry Andric // Add the given capabilities and all their implicitly defined capabilities too. 522bdd1243dSDimitry Andric void SPIRV::RequirementHandler::addAvailableCaps(const CapabilityList &ToAdd) { 523bdd1243dSDimitry Andric for (const auto Cap : ToAdd) 524bdd1243dSDimitry Andric if (AvailableCaps.insert(Cap).second) 525bdd1243dSDimitry Andric addAvailableCaps(getSymbolicOperandCapabilities( 526bdd1243dSDimitry Andric SPIRV::OperandCategory::CapabilityOperand, Cap)); 527bdd1243dSDimitry Andric } 528bdd1243dSDimitry Andric 5295f757f3fSDimitry Andric void SPIRV::RequirementHandler::removeCapabilityIf( 5305f757f3fSDimitry Andric const Capability::Capability ToRemove, 5315f757f3fSDimitry Andric const Capability::Capability IfPresent) { 5325f757f3fSDimitry Andric if (AllCaps.contains(IfPresent)) 5335f757f3fSDimitry Andric AllCaps.erase(ToRemove); 5345f757f3fSDimitry Andric } 5355f757f3fSDimitry Andric 536bdd1243dSDimitry Andric namespace llvm { 537bdd1243dSDimitry Andric namespace SPIRV { 538bdd1243dSDimitry Andric void RequirementHandler::initAvailableCapabilities(const SPIRVSubtarget &ST) { 5395f757f3fSDimitry Andric if (ST.isOpenCLEnv()) { 5405f757f3fSDimitry Andric initAvailableCapabilitiesForOpenCL(ST); 541bdd1243dSDimitry Andric return; 5425f757f3fSDimitry Andric } 5435f757f3fSDimitry Andric 5445f757f3fSDimitry Andric if (ST.isVulkanEnv()) { 5455f757f3fSDimitry Andric initAvailableCapabilitiesForVulkan(ST); 5465f757f3fSDimitry Andric return; 5475f757f3fSDimitry Andric } 5485f757f3fSDimitry Andric 5495f757f3fSDimitry Andric report_fatal_error("Unimplemented environment for SPIR-V generation."); 5505f757f3fSDimitry Andric } 5515f757f3fSDimitry Andric 5525f757f3fSDimitry Andric void RequirementHandler::initAvailableCapabilitiesForOpenCL( 5535f757f3fSDimitry Andric const SPIRVSubtarget &ST) { 554bdd1243dSDimitry Andric // Add the min requirements for different OpenCL and SPIR-V versions. 555bdd1243dSDimitry Andric addAvailableCaps({Capability::Addresses, Capability::Float16Buffer, 556bdd1243dSDimitry Andric Capability::Int16, Capability::Int8, Capability::Kernel, 557bdd1243dSDimitry Andric Capability::Linkage, Capability::Vector16, 558bdd1243dSDimitry Andric Capability::Groups, Capability::GenericPointer, 559bdd1243dSDimitry Andric Capability::Shader}); 560bdd1243dSDimitry Andric if (ST.hasOpenCLFullProfile()) 561bdd1243dSDimitry Andric addAvailableCaps({Capability::Int64, Capability::Int64Atomics}); 562bdd1243dSDimitry Andric if (ST.hasOpenCLImageSupport()) { 563bdd1243dSDimitry Andric addAvailableCaps({Capability::ImageBasic, Capability::LiteralSampler, 564bdd1243dSDimitry Andric Capability::Image1D, Capability::SampledBuffer, 565bdd1243dSDimitry Andric Capability::ImageBuffer}); 566bdd1243dSDimitry Andric if (ST.isAtLeastOpenCLVer(20)) 567bdd1243dSDimitry Andric addAvailableCaps({Capability::ImageReadWrite}); 568bdd1243dSDimitry Andric } 569bdd1243dSDimitry Andric if (ST.isAtLeastSPIRVVer(11) && ST.isAtLeastOpenCLVer(22)) 570bdd1243dSDimitry Andric addAvailableCaps({Capability::SubgroupDispatch, Capability::PipeStorage}); 571bdd1243dSDimitry Andric if (ST.isAtLeastSPIRVVer(13)) 572bdd1243dSDimitry Andric addAvailableCaps({Capability::GroupNonUniform, 573bdd1243dSDimitry Andric Capability::GroupNonUniformVote, 574bdd1243dSDimitry Andric Capability::GroupNonUniformArithmetic, 575bdd1243dSDimitry Andric Capability::GroupNonUniformBallot, 576bdd1243dSDimitry Andric Capability::GroupNonUniformClustered, 577bdd1243dSDimitry Andric Capability::GroupNonUniformShuffle, 578bdd1243dSDimitry Andric Capability::GroupNonUniformShuffleRelative}); 579bdd1243dSDimitry Andric if (ST.isAtLeastSPIRVVer(14)) 580bdd1243dSDimitry Andric addAvailableCaps({Capability::DenormPreserve, Capability::DenormFlushToZero, 581bdd1243dSDimitry Andric Capability::SignedZeroInfNanPreserve, 582bdd1243dSDimitry Andric Capability::RoundingModeRTE, 583bdd1243dSDimitry Andric Capability::RoundingModeRTZ}); 584bdd1243dSDimitry Andric // TODO: verify if this needs some checks. 585bdd1243dSDimitry Andric addAvailableCaps({Capability::Float16, Capability::Float64}); 586bdd1243dSDimitry Andric 5875f757f3fSDimitry Andric // Add capabilities enabled by extensions. 5885f757f3fSDimitry Andric for (auto Extension : ST.getAllAvailableExtensions()) { 5895f757f3fSDimitry Andric CapabilityList EnabledCapabilities = 5905f757f3fSDimitry Andric getCapabilitiesEnabledByExtension(Extension); 5915f757f3fSDimitry Andric addAvailableCaps(EnabledCapabilities); 5925f757f3fSDimitry Andric } 5935f757f3fSDimitry Andric 594bdd1243dSDimitry Andric // TODO: add OpenCL extensions. 595bdd1243dSDimitry Andric } 5965f757f3fSDimitry Andric 5975f757f3fSDimitry Andric void RequirementHandler::initAvailableCapabilitiesForVulkan( 5985f757f3fSDimitry Andric const SPIRVSubtarget &ST) { 5995f757f3fSDimitry Andric addAvailableCaps({Capability::Shader, Capability::Linkage}); 6005f757f3fSDimitry Andric 601*7a6dacacSDimitry Andric // Provided by all supported Vulkan versions. 602*7a6dacacSDimitry Andric addAvailableCaps({Capability::Int16, Capability::Int64, Capability::Float16, 603*7a6dacacSDimitry Andric Capability::Float64}); 6045f757f3fSDimitry Andric } 6055f757f3fSDimitry Andric 606bdd1243dSDimitry Andric } // namespace SPIRV 607bdd1243dSDimitry Andric } // namespace llvm 608bdd1243dSDimitry Andric 609bdd1243dSDimitry Andric // Add the required capabilities from a decoration instruction (including 610bdd1243dSDimitry Andric // BuiltIns). 611bdd1243dSDimitry Andric static void addOpDecorateReqs(const MachineInstr &MI, unsigned DecIndex, 612bdd1243dSDimitry Andric SPIRV::RequirementHandler &Reqs, 613bdd1243dSDimitry Andric const SPIRVSubtarget &ST) { 614bdd1243dSDimitry Andric int64_t DecOp = MI.getOperand(DecIndex).getImm(); 615bdd1243dSDimitry Andric auto Dec = static_cast<SPIRV::Decoration::Decoration>(DecOp); 616bdd1243dSDimitry Andric Reqs.addRequirements(getSymbolicOperandRequirements( 617bdd1243dSDimitry Andric SPIRV::OperandCategory::DecorationOperand, Dec, ST, Reqs)); 618bdd1243dSDimitry Andric 619bdd1243dSDimitry Andric if (Dec == SPIRV::Decoration::BuiltIn) { 620bdd1243dSDimitry Andric int64_t BuiltInOp = MI.getOperand(DecIndex + 1).getImm(); 621bdd1243dSDimitry Andric auto BuiltIn = static_cast<SPIRV::BuiltIn::BuiltIn>(BuiltInOp); 622bdd1243dSDimitry Andric Reqs.addRequirements(getSymbolicOperandRequirements( 623bdd1243dSDimitry Andric SPIRV::OperandCategory::BuiltInOperand, BuiltIn, ST, Reqs)); 624bdd1243dSDimitry Andric } 625bdd1243dSDimitry Andric } 626bdd1243dSDimitry Andric 627bdd1243dSDimitry Andric // Add requirements for image handling. 628bdd1243dSDimitry Andric static void addOpTypeImageReqs(const MachineInstr &MI, 629bdd1243dSDimitry Andric SPIRV::RequirementHandler &Reqs, 630bdd1243dSDimitry Andric const SPIRVSubtarget &ST) { 631bdd1243dSDimitry Andric assert(MI.getNumOperands() >= 8 && "Insufficient operands for OpTypeImage"); 632bdd1243dSDimitry Andric // The operand indices used here are based on the OpTypeImage layout, which 633bdd1243dSDimitry Andric // the MachineInstr follows as well. 634bdd1243dSDimitry Andric int64_t ImgFormatOp = MI.getOperand(7).getImm(); 635bdd1243dSDimitry Andric auto ImgFormat = static_cast<SPIRV::ImageFormat::ImageFormat>(ImgFormatOp); 636bdd1243dSDimitry Andric Reqs.getAndAddRequirements(SPIRV::OperandCategory::ImageFormatOperand, 637bdd1243dSDimitry Andric ImgFormat, ST); 638bdd1243dSDimitry Andric 639bdd1243dSDimitry Andric bool IsArrayed = MI.getOperand(4).getImm() == 1; 640bdd1243dSDimitry Andric bool IsMultisampled = MI.getOperand(5).getImm() == 1; 641bdd1243dSDimitry Andric bool NoSampler = MI.getOperand(6).getImm() == 2; 642bdd1243dSDimitry Andric // Add dimension requirements. 643bdd1243dSDimitry Andric assert(MI.getOperand(2).isImm()); 644bdd1243dSDimitry Andric switch (MI.getOperand(2).getImm()) { 645bdd1243dSDimitry Andric case SPIRV::Dim::DIM_1D: 646bdd1243dSDimitry Andric Reqs.addRequirements(NoSampler ? SPIRV::Capability::Image1D 647bdd1243dSDimitry Andric : SPIRV::Capability::Sampled1D); 648bdd1243dSDimitry Andric break; 649bdd1243dSDimitry Andric case SPIRV::Dim::DIM_2D: 650bdd1243dSDimitry Andric if (IsMultisampled && NoSampler) 651bdd1243dSDimitry Andric Reqs.addRequirements(SPIRV::Capability::ImageMSArray); 652bdd1243dSDimitry Andric break; 653bdd1243dSDimitry Andric case SPIRV::Dim::DIM_Cube: 654bdd1243dSDimitry Andric Reqs.addRequirements(SPIRV::Capability::Shader); 655bdd1243dSDimitry Andric if (IsArrayed) 656bdd1243dSDimitry Andric Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageCubeArray 657bdd1243dSDimitry Andric : SPIRV::Capability::SampledCubeArray); 658bdd1243dSDimitry Andric break; 659bdd1243dSDimitry Andric case SPIRV::Dim::DIM_Rect: 660bdd1243dSDimitry Andric Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageRect 661bdd1243dSDimitry Andric : SPIRV::Capability::SampledRect); 662bdd1243dSDimitry Andric break; 663bdd1243dSDimitry Andric case SPIRV::Dim::DIM_Buffer: 664bdd1243dSDimitry Andric Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageBuffer 665bdd1243dSDimitry Andric : SPIRV::Capability::SampledBuffer); 666bdd1243dSDimitry Andric break; 667bdd1243dSDimitry Andric case SPIRV::Dim::DIM_SubpassData: 668bdd1243dSDimitry Andric Reqs.addRequirements(SPIRV::Capability::InputAttachment); 669bdd1243dSDimitry Andric break; 670bdd1243dSDimitry Andric } 671bdd1243dSDimitry Andric 672bdd1243dSDimitry Andric // Has optional access qualifier. 673bdd1243dSDimitry Andric // TODO: check if it's OpenCL's kernel. 674bdd1243dSDimitry Andric if (MI.getNumOperands() > 8 && 675bdd1243dSDimitry Andric MI.getOperand(8).getImm() == SPIRV::AccessQualifier::ReadWrite) 676bdd1243dSDimitry Andric Reqs.addRequirements(SPIRV::Capability::ImageReadWrite); 677bdd1243dSDimitry Andric else 678bdd1243dSDimitry Andric Reqs.addRequirements(SPIRV::Capability::ImageBasic); 679bdd1243dSDimitry Andric } 680bdd1243dSDimitry Andric 681bdd1243dSDimitry Andric void addInstrRequirements(const MachineInstr &MI, 682bdd1243dSDimitry Andric SPIRV::RequirementHandler &Reqs, 683bdd1243dSDimitry Andric const SPIRVSubtarget &ST) { 684bdd1243dSDimitry Andric switch (MI.getOpcode()) { 685bdd1243dSDimitry Andric case SPIRV::OpMemoryModel: { 686bdd1243dSDimitry Andric int64_t Addr = MI.getOperand(0).getImm(); 687bdd1243dSDimitry Andric Reqs.getAndAddRequirements(SPIRV::OperandCategory::AddressingModelOperand, 688bdd1243dSDimitry Andric Addr, ST); 689bdd1243dSDimitry Andric int64_t Mem = MI.getOperand(1).getImm(); 690bdd1243dSDimitry Andric Reqs.getAndAddRequirements(SPIRV::OperandCategory::MemoryModelOperand, Mem, 691bdd1243dSDimitry Andric ST); 692bdd1243dSDimitry Andric break; 693bdd1243dSDimitry Andric } 694bdd1243dSDimitry Andric case SPIRV::OpEntryPoint: { 695bdd1243dSDimitry Andric int64_t Exe = MI.getOperand(0).getImm(); 696bdd1243dSDimitry Andric Reqs.getAndAddRequirements(SPIRV::OperandCategory::ExecutionModelOperand, 697bdd1243dSDimitry Andric Exe, ST); 698bdd1243dSDimitry Andric break; 699bdd1243dSDimitry Andric } 700bdd1243dSDimitry Andric case SPIRV::OpExecutionMode: 701bdd1243dSDimitry Andric case SPIRV::OpExecutionModeId: { 702bdd1243dSDimitry Andric int64_t Exe = MI.getOperand(1).getImm(); 703bdd1243dSDimitry Andric Reqs.getAndAddRequirements(SPIRV::OperandCategory::ExecutionModeOperand, 704bdd1243dSDimitry Andric Exe, ST); 705bdd1243dSDimitry Andric break; 706bdd1243dSDimitry Andric } 707bdd1243dSDimitry Andric case SPIRV::OpTypeMatrix: 708bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Matrix); 709bdd1243dSDimitry Andric break; 710bdd1243dSDimitry Andric case SPIRV::OpTypeInt: { 711bdd1243dSDimitry Andric unsigned BitWidth = MI.getOperand(1).getImm(); 712bdd1243dSDimitry Andric if (BitWidth == 64) 713bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Int64); 714bdd1243dSDimitry Andric else if (BitWidth == 16) 715bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Int16); 716bdd1243dSDimitry Andric else if (BitWidth == 8) 717bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Int8); 718bdd1243dSDimitry Andric break; 719bdd1243dSDimitry Andric } 720bdd1243dSDimitry Andric case SPIRV::OpTypeFloat: { 721bdd1243dSDimitry Andric unsigned BitWidth = MI.getOperand(1).getImm(); 722bdd1243dSDimitry Andric if (BitWidth == 64) 723bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Float64); 724bdd1243dSDimitry Andric else if (BitWidth == 16) 725bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Float16); 726bdd1243dSDimitry Andric break; 727bdd1243dSDimitry Andric } 728bdd1243dSDimitry Andric case SPIRV::OpTypeVector: { 729bdd1243dSDimitry Andric unsigned NumComponents = MI.getOperand(2).getImm(); 730bdd1243dSDimitry Andric if (NumComponents == 8 || NumComponents == 16) 731bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Vector16); 732bdd1243dSDimitry Andric break; 733bdd1243dSDimitry Andric } 734bdd1243dSDimitry Andric case SPIRV::OpTypePointer: { 735bdd1243dSDimitry Andric auto SC = MI.getOperand(1).getImm(); 736bdd1243dSDimitry Andric Reqs.getAndAddRequirements(SPIRV::OperandCategory::StorageClassOperand, SC, 737bdd1243dSDimitry Andric ST); 738*7a6dacacSDimitry Andric // If it's a type of pointer to float16 targeting OpenCL, add Float16Buffer 739*7a6dacacSDimitry Andric // capability. 740*7a6dacacSDimitry Andric if (!ST.isOpenCLEnv()) 741*7a6dacacSDimitry Andric break; 742bdd1243dSDimitry Andric assert(MI.getOperand(2).isReg()); 743bdd1243dSDimitry Andric const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo(); 744bdd1243dSDimitry Andric SPIRVType *TypeDef = MRI.getVRegDef(MI.getOperand(2).getReg()); 745bdd1243dSDimitry Andric if (TypeDef->getOpcode() == SPIRV::OpTypeFloat && 746bdd1243dSDimitry Andric TypeDef->getOperand(1).getImm() == 16) 747bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Float16Buffer); 748bdd1243dSDimitry Andric break; 749bdd1243dSDimitry Andric } 750bdd1243dSDimitry Andric case SPIRV::OpBitReverse: 7515f757f3fSDimitry Andric case SPIRV::OpBitFieldInsert: 7525f757f3fSDimitry Andric case SPIRV::OpBitFieldSExtract: 7535f757f3fSDimitry Andric case SPIRV::OpBitFieldUExtract: 7545f757f3fSDimitry Andric if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions)) { 7555f757f3fSDimitry Andric Reqs.addCapability(SPIRV::Capability::Shader); 7565f757f3fSDimitry Andric break; 7575f757f3fSDimitry Andric } 7585f757f3fSDimitry Andric Reqs.addExtension(SPIRV::Extension::SPV_KHR_bit_instructions); 7595f757f3fSDimitry Andric Reqs.addCapability(SPIRV::Capability::BitInstructions); 7605f757f3fSDimitry Andric break; 761bdd1243dSDimitry Andric case SPIRV::OpTypeRuntimeArray: 762bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Shader); 763bdd1243dSDimitry Andric break; 764bdd1243dSDimitry Andric case SPIRV::OpTypeOpaque: 765bdd1243dSDimitry Andric case SPIRV::OpTypeEvent: 766bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Kernel); 767bdd1243dSDimitry Andric break; 768bdd1243dSDimitry Andric case SPIRV::OpTypePipe: 769bdd1243dSDimitry Andric case SPIRV::OpTypeReserveId: 770bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Pipes); 771bdd1243dSDimitry Andric break; 772bdd1243dSDimitry Andric case SPIRV::OpTypeDeviceEvent: 773bdd1243dSDimitry Andric case SPIRV::OpTypeQueue: 774bdd1243dSDimitry Andric case SPIRV::OpBuildNDRange: 775bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::DeviceEnqueue); 776bdd1243dSDimitry Andric break; 777bdd1243dSDimitry Andric case SPIRV::OpDecorate: 778bdd1243dSDimitry Andric case SPIRV::OpDecorateId: 779bdd1243dSDimitry Andric case SPIRV::OpDecorateString: 780bdd1243dSDimitry Andric addOpDecorateReqs(MI, 1, Reqs, ST); 781bdd1243dSDimitry Andric break; 782bdd1243dSDimitry Andric case SPIRV::OpMemberDecorate: 783bdd1243dSDimitry Andric case SPIRV::OpMemberDecorateString: 784bdd1243dSDimitry Andric addOpDecorateReqs(MI, 2, Reqs, ST); 785bdd1243dSDimitry Andric break; 786bdd1243dSDimitry Andric case SPIRV::OpInBoundsPtrAccessChain: 787bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Addresses); 788bdd1243dSDimitry Andric break; 789bdd1243dSDimitry Andric case SPIRV::OpConstantSampler: 790bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::LiteralSampler); 791bdd1243dSDimitry Andric break; 792bdd1243dSDimitry Andric case SPIRV::OpTypeImage: 793bdd1243dSDimitry Andric addOpTypeImageReqs(MI, Reqs, ST); 794bdd1243dSDimitry Andric break; 795bdd1243dSDimitry Andric case SPIRV::OpTypeSampler: 796bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::ImageBasic); 797bdd1243dSDimitry Andric break; 798bdd1243dSDimitry Andric case SPIRV::OpTypeForwardPointer: 799bdd1243dSDimitry Andric // TODO: check if it's OpenCL's kernel. 800bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Addresses); 801bdd1243dSDimitry Andric break; 802bdd1243dSDimitry Andric case SPIRV::OpAtomicFlagTestAndSet: 803bdd1243dSDimitry Andric case SPIRV::OpAtomicLoad: 804bdd1243dSDimitry Andric case SPIRV::OpAtomicStore: 805bdd1243dSDimitry Andric case SPIRV::OpAtomicExchange: 806bdd1243dSDimitry Andric case SPIRV::OpAtomicCompareExchange: 807bdd1243dSDimitry Andric case SPIRV::OpAtomicIIncrement: 808bdd1243dSDimitry Andric case SPIRV::OpAtomicIDecrement: 809bdd1243dSDimitry Andric case SPIRV::OpAtomicIAdd: 810bdd1243dSDimitry Andric case SPIRV::OpAtomicISub: 811bdd1243dSDimitry Andric case SPIRV::OpAtomicUMin: 812bdd1243dSDimitry Andric case SPIRV::OpAtomicUMax: 813bdd1243dSDimitry Andric case SPIRV::OpAtomicSMin: 814bdd1243dSDimitry Andric case SPIRV::OpAtomicSMax: 815bdd1243dSDimitry Andric case SPIRV::OpAtomicAnd: 816bdd1243dSDimitry Andric case SPIRV::OpAtomicOr: 817bdd1243dSDimitry Andric case SPIRV::OpAtomicXor: { 818bdd1243dSDimitry Andric const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo(); 819bdd1243dSDimitry Andric const MachineInstr *InstrPtr = &MI; 820bdd1243dSDimitry Andric if (MI.getOpcode() == SPIRV::OpAtomicStore) { 821bdd1243dSDimitry Andric assert(MI.getOperand(3).isReg()); 822bdd1243dSDimitry Andric InstrPtr = MRI.getVRegDef(MI.getOperand(3).getReg()); 823bdd1243dSDimitry Andric assert(InstrPtr && "Unexpected type instruction for OpAtomicStore"); 824bdd1243dSDimitry Andric } 825bdd1243dSDimitry Andric assert(InstrPtr->getOperand(1).isReg() && "Unexpected operand in atomic"); 826bdd1243dSDimitry Andric Register TypeReg = InstrPtr->getOperand(1).getReg(); 827bdd1243dSDimitry Andric SPIRVType *TypeDef = MRI.getVRegDef(TypeReg); 828bdd1243dSDimitry Andric if (TypeDef->getOpcode() == SPIRV::OpTypeInt) { 829bdd1243dSDimitry Andric unsigned BitWidth = TypeDef->getOperand(1).getImm(); 830bdd1243dSDimitry Andric if (BitWidth == 64) 831bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Int64Atomics); 832bdd1243dSDimitry Andric } 833bdd1243dSDimitry Andric break; 834bdd1243dSDimitry Andric } 835bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformIAdd: 836bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformFAdd: 837bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformIMul: 838bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformFMul: 839bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformSMin: 840bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformUMin: 841bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformFMin: 842bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformSMax: 843bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformUMax: 844bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformFMax: 845bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformBitwiseAnd: 846bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformBitwiseOr: 847bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformBitwiseXor: 848bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformLogicalAnd: 849bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformLogicalOr: 850bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformLogicalXor: { 851bdd1243dSDimitry Andric assert(MI.getOperand(3).isImm()); 852bdd1243dSDimitry Andric int64_t GroupOp = MI.getOperand(3).getImm(); 853bdd1243dSDimitry Andric switch (GroupOp) { 854bdd1243dSDimitry Andric case SPIRV::GroupOperation::Reduce: 855bdd1243dSDimitry Andric case SPIRV::GroupOperation::InclusiveScan: 856bdd1243dSDimitry Andric case SPIRV::GroupOperation::ExclusiveScan: 857bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Kernel); 858bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::GroupNonUniformArithmetic); 859bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::GroupNonUniformBallot); 860bdd1243dSDimitry Andric break; 861bdd1243dSDimitry Andric case SPIRV::GroupOperation::ClusteredReduce: 862bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::GroupNonUniformClustered); 863bdd1243dSDimitry Andric break; 864bdd1243dSDimitry Andric case SPIRV::GroupOperation::PartitionedReduceNV: 865bdd1243dSDimitry Andric case SPIRV::GroupOperation::PartitionedInclusiveScanNV: 866bdd1243dSDimitry Andric case SPIRV::GroupOperation::PartitionedExclusiveScanNV: 867bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::GroupNonUniformPartitionedNV); 868bdd1243dSDimitry Andric break; 869bdd1243dSDimitry Andric } 870bdd1243dSDimitry Andric break; 871bdd1243dSDimitry Andric } 872bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformShuffle: 873bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformShuffleXor: 874bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::GroupNonUniformShuffle); 875bdd1243dSDimitry Andric break; 876bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformShuffleUp: 877bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformShuffleDown: 878bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::GroupNonUniformShuffleRelative); 879bdd1243dSDimitry Andric break; 880bdd1243dSDimitry Andric case SPIRV::OpGroupAll: 881bdd1243dSDimitry Andric case SPIRV::OpGroupAny: 882bdd1243dSDimitry Andric case SPIRV::OpGroupBroadcast: 883bdd1243dSDimitry Andric case SPIRV::OpGroupIAdd: 884bdd1243dSDimitry Andric case SPIRV::OpGroupFAdd: 885bdd1243dSDimitry Andric case SPIRV::OpGroupFMin: 886bdd1243dSDimitry Andric case SPIRV::OpGroupUMin: 887bdd1243dSDimitry Andric case SPIRV::OpGroupSMin: 888bdd1243dSDimitry Andric case SPIRV::OpGroupFMax: 889bdd1243dSDimitry Andric case SPIRV::OpGroupUMax: 890bdd1243dSDimitry Andric case SPIRV::OpGroupSMax: 891bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Groups); 892bdd1243dSDimitry Andric break; 893bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformElect: 894bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::GroupNonUniform); 895bdd1243dSDimitry Andric break; 896bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformAll: 897bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformAny: 898bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformAllEqual: 899bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::GroupNonUniformVote); 900bdd1243dSDimitry Andric break; 901bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformBroadcast: 902bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformBroadcastFirst: 903bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformBallot: 904bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformInverseBallot: 905bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformBallotBitExtract: 906bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformBallotBitCount: 907bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformBallotFindLSB: 908bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformBallotFindMSB: 909bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::GroupNonUniformBallot); 910bdd1243dSDimitry Andric break; 9115f757f3fSDimitry Andric case SPIRV::OpAssumeTrueKHR: 9125f757f3fSDimitry Andric case SPIRV::OpExpectKHR: 9135f757f3fSDimitry Andric if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) { 9145f757f3fSDimitry Andric Reqs.addExtension(SPIRV::Extension::SPV_KHR_expect_assume); 9155f757f3fSDimitry Andric Reqs.addCapability(SPIRV::Capability::ExpectAssumeKHR); 9165f757f3fSDimitry Andric } 9175f757f3fSDimitry Andric break; 918bdd1243dSDimitry Andric default: 919bdd1243dSDimitry Andric break; 920bdd1243dSDimitry Andric } 9215f757f3fSDimitry Andric 9225f757f3fSDimitry Andric // If we require capability Shader, then we can remove the requirement for 9235f757f3fSDimitry Andric // the BitInstructions capability, since Shader is a superset capability 9245f757f3fSDimitry Andric // of BitInstructions. 9255f757f3fSDimitry Andric Reqs.removeCapabilityIf(SPIRV::Capability::BitInstructions, 9265f757f3fSDimitry Andric SPIRV::Capability::Shader); 927bdd1243dSDimitry Andric } 928bdd1243dSDimitry Andric 929bdd1243dSDimitry Andric static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI, 930bdd1243dSDimitry Andric MachineModuleInfo *MMI, const SPIRVSubtarget &ST) { 931bdd1243dSDimitry Andric // Collect requirements for existing instructions. 932bdd1243dSDimitry Andric for (auto F = M.begin(), E = M.end(); F != E; ++F) { 933bdd1243dSDimitry Andric MachineFunction *MF = MMI->getMachineFunction(*F); 934bdd1243dSDimitry Andric if (!MF) 935bdd1243dSDimitry Andric continue; 936bdd1243dSDimitry Andric for (const MachineBasicBlock &MBB : *MF) 937bdd1243dSDimitry Andric for (const MachineInstr &MI : MBB) 938bdd1243dSDimitry Andric addInstrRequirements(MI, MAI.Reqs, ST); 939bdd1243dSDimitry Andric } 940bdd1243dSDimitry Andric // Collect requirements for OpExecutionMode instructions. 941bdd1243dSDimitry Andric auto Node = M.getNamedMetadata("spirv.ExecutionMode"); 942bdd1243dSDimitry Andric if (Node) { 943bdd1243dSDimitry Andric for (unsigned i = 0; i < Node->getNumOperands(); i++) { 944bdd1243dSDimitry Andric MDNode *MDN = cast<MDNode>(Node->getOperand(i)); 945bdd1243dSDimitry Andric const MDOperand &MDOp = MDN->getOperand(1); 946bdd1243dSDimitry Andric if (auto *CMeta = dyn_cast<ConstantAsMetadata>(MDOp)) { 947bdd1243dSDimitry Andric Constant *C = CMeta->getValue(); 948bdd1243dSDimitry Andric if (ConstantInt *Const = dyn_cast<ConstantInt>(C)) { 949bdd1243dSDimitry Andric auto EM = Const->getZExtValue(); 950bdd1243dSDimitry Andric MAI.Reqs.getAndAddRequirements( 951bdd1243dSDimitry Andric SPIRV::OperandCategory::ExecutionModeOperand, EM, ST); 952bdd1243dSDimitry Andric } 953bdd1243dSDimitry Andric } 954bdd1243dSDimitry Andric } 955bdd1243dSDimitry Andric } 956bdd1243dSDimitry Andric for (auto FI = M.begin(), E = M.end(); FI != E; ++FI) { 957bdd1243dSDimitry Andric const Function &F = *FI; 958bdd1243dSDimitry Andric if (F.isDeclaration()) 959bdd1243dSDimitry Andric continue; 960bdd1243dSDimitry Andric if (F.getMetadata("reqd_work_group_size")) 961bdd1243dSDimitry Andric MAI.Reqs.getAndAddRequirements( 962bdd1243dSDimitry Andric SPIRV::OperandCategory::ExecutionModeOperand, 963bdd1243dSDimitry Andric SPIRV::ExecutionMode::LocalSize, ST); 9645f757f3fSDimitry Andric if (F.getFnAttribute("hlsl.numthreads").isValid()) { 9655f757f3fSDimitry Andric MAI.Reqs.getAndAddRequirements( 9665f757f3fSDimitry Andric SPIRV::OperandCategory::ExecutionModeOperand, 9675f757f3fSDimitry Andric SPIRV::ExecutionMode::LocalSize, ST); 9685f757f3fSDimitry Andric } 969bdd1243dSDimitry Andric if (F.getMetadata("work_group_size_hint")) 970bdd1243dSDimitry Andric MAI.Reqs.getAndAddRequirements( 971bdd1243dSDimitry Andric SPIRV::OperandCategory::ExecutionModeOperand, 972bdd1243dSDimitry Andric SPIRV::ExecutionMode::LocalSizeHint, ST); 973bdd1243dSDimitry Andric if (F.getMetadata("intel_reqd_sub_group_size")) 974bdd1243dSDimitry Andric MAI.Reqs.getAndAddRequirements( 975bdd1243dSDimitry Andric SPIRV::OperandCategory::ExecutionModeOperand, 976bdd1243dSDimitry Andric SPIRV::ExecutionMode::SubgroupSize, ST); 977bdd1243dSDimitry Andric if (F.getMetadata("vec_type_hint")) 978bdd1243dSDimitry Andric MAI.Reqs.getAndAddRequirements( 979bdd1243dSDimitry Andric SPIRV::OperandCategory::ExecutionModeOperand, 980bdd1243dSDimitry Andric SPIRV::ExecutionMode::VecTypeHint, ST); 9815f757f3fSDimitry Andric 9825f757f3fSDimitry Andric if (F.hasOptNone() && 9835f757f3fSDimitry Andric ST.canUseExtension(SPIRV::Extension::SPV_INTEL_optnone)) { 9845f757f3fSDimitry Andric // Output OpCapability OptNoneINTEL. 9855f757f3fSDimitry Andric MAI.Reqs.addExtension(SPIRV::Extension::SPV_INTEL_optnone); 9865f757f3fSDimitry Andric MAI.Reqs.addCapability(SPIRV::Capability::OptNoneINTEL); 9875f757f3fSDimitry Andric } 988bdd1243dSDimitry Andric } 989bdd1243dSDimitry Andric } 990bdd1243dSDimitry Andric 991bdd1243dSDimitry Andric static unsigned getFastMathFlags(const MachineInstr &I) { 992bdd1243dSDimitry Andric unsigned Flags = SPIRV::FPFastMathMode::None; 993bdd1243dSDimitry Andric if (I.getFlag(MachineInstr::MIFlag::FmNoNans)) 994bdd1243dSDimitry Andric Flags |= SPIRV::FPFastMathMode::NotNaN; 995bdd1243dSDimitry Andric if (I.getFlag(MachineInstr::MIFlag::FmNoInfs)) 996bdd1243dSDimitry Andric Flags |= SPIRV::FPFastMathMode::NotInf; 997bdd1243dSDimitry Andric if (I.getFlag(MachineInstr::MIFlag::FmNsz)) 998bdd1243dSDimitry Andric Flags |= SPIRV::FPFastMathMode::NSZ; 999bdd1243dSDimitry Andric if (I.getFlag(MachineInstr::MIFlag::FmArcp)) 1000bdd1243dSDimitry Andric Flags |= SPIRV::FPFastMathMode::AllowRecip; 1001bdd1243dSDimitry Andric if (I.getFlag(MachineInstr::MIFlag::FmReassoc)) 1002bdd1243dSDimitry Andric Flags |= SPIRV::FPFastMathMode::Fast; 1003bdd1243dSDimitry Andric return Flags; 1004bdd1243dSDimitry Andric } 1005bdd1243dSDimitry Andric 1006bdd1243dSDimitry Andric static void handleMIFlagDecoration(MachineInstr &I, const SPIRVSubtarget &ST, 1007bdd1243dSDimitry Andric const SPIRVInstrInfo &TII, 1008bdd1243dSDimitry Andric SPIRV::RequirementHandler &Reqs) { 1009bdd1243dSDimitry Andric if (I.getFlag(MachineInstr::MIFlag::NoSWrap) && TII.canUseNSW(I) && 1010bdd1243dSDimitry Andric getSymbolicOperandRequirements(SPIRV::OperandCategory::DecorationOperand, 1011bdd1243dSDimitry Andric SPIRV::Decoration::NoSignedWrap, ST, Reqs) 1012bdd1243dSDimitry Andric .IsSatisfiable) { 1013bdd1243dSDimitry Andric buildOpDecorate(I.getOperand(0).getReg(), I, TII, 1014bdd1243dSDimitry Andric SPIRV::Decoration::NoSignedWrap, {}); 1015bdd1243dSDimitry Andric } 1016bdd1243dSDimitry Andric if (I.getFlag(MachineInstr::MIFlag::NoUWrap) && TII.canUseNUW(I) && 1017bdd1243dSDimitry Andric getSymbolicOperandRequirements(SPIRV::OperandCategory::DecorationOperand, 1018bdd1243dSDimitry Andric SPIRV::Decoration::NoUnsignedWrap, ST, 1019bdd1243dSDimitry Andric Reqs) 1020bdd1243dSDimitry Andric .IsSatisfiable) { 1021bdd1243dSDimitry Andric buildOpDecorate(I.getOperand(0).getReg(), I, TII, 1022bdd1243dSDimitry Andric SPIRV::Decoration::NoUnsignedWrap, {}); 1023bdd1243dSDimitry Andric } 1024bdd1243dSDimitry Andric if (!TII.canUseFastMathFlags(I)) 1025bdd1243dSDimitry Andric return; 1026bdd1243dSDimitry Andric unsigned FMFlags = getFastMathFlags(I); 1027bdd1243dSDimitry Andric if (FMFlags == SPIRV::FPFastMathMode::None) 1028bdd1243dSDimitry Andric return; 1029bdd1243dSDimitry Andric Register DstReg = I.getOperand(0).getReg(); 1030bdd1243dSDimitry Andric buildOpDecorate(DstReg, I, TII, SPIRV::Decoration::FPFastMathMode, {FMFlags}); 1031bdd1243dSDimitry Andric } 1032bdd1243dSDimitry Andric 1033bdd1243dSDimitry Andric // Walk all functions and add decorations related to MI flags. 1034bdd1243dSDimitry Andric static void addDecorations(const Module &M, const SPIRVInstrInfo &TII, 1035bdd1243dSDimitry Andric MachineModuleInfo *MMI, const SPIRVSubtarget &ST, 1036bdd1243dSDimitry Andric SPIRV::ModuleAnalysisInfo &MAI) { 1037bdd1243dSDimitry Andric for (auto F = M.begin(), E = M.end(); F != E; ++F) { 1038bdd1243dSDimitry Andric MachineFunction *MF = MMI->getMachineFunction(*F); 1039bdd1243dSDimitry Andric if (!MF) 1040bdd1243dSDimitry Andric continue; 1041bdd1243dSDimitry Andric for (auto &MBB : *MF) 1042bdd1243dSDimitry Andric for (auto &MI : MBB) 1043bdd1243dSDimitry Andric handleMIFlagDecoration(MI, ST, TII, MAI.Reqs); 1044bdd1243dSDimitry Andric } 1045bdd1243dSDimitry Andric } 1046bdd1243dSDimitry Andric 104781ad6265SDimitry Andric struct SPIRV::ModuleAnalysisInfo SPIRVModuleAnalysis::MAI; 104881ad6265SDimitry Andric 104981ad6265SDimitry Andric void SPIRVModuleAnalysis::getAnalysisUsage(AnalysisUsage &AU) const { 105081ad6265SDimitry Andric AU.addRequired<TargetPassConfig>(); 105181ad6265SDimitry Andric AU.addRequired<MachineModuleInfoWrapperPass>(); 105281ad6265SDimitry Andric } 105381ad6265SDimitry Andric 105481ad6265SDimitry Andric bool SPIRVModuleAnalysis::runOnModule(Module &M) { 105581ad6265SDimitry Andric SPIRVTargetMachine &TM = 105681ad6265SDimitry Andric getAnalysis<TargetPassConfig>().getTM<SPIRVTargetMachine>(); 105781ad6265SDimitry Andric ST = TM.getSubtargetImpl(); 105881ad6265SDimitry Andric GR = ST->getSPIRVGlobalRegistry(); 105981ad6265SDimitry Andric TII = ST->getInstrInfo(); 106081ad6265SDimitry Andric 106181ad6265SDimitry Andric MMI = &getAnalysis<MachineModuleInfoWrapperPass>().getMMI(); 106281ad6265SDimitry Andric 106381ad6265SDimitry Andric setBaseInfo(M); 106481ad6265SDimitry Andric 1065bdd1243dSDimitry Andric addDecorations(M, *TII, MMI, *ST, MAI); 1066bdd1243dSDimitry Andric 1067bdd1243dSDimitry Andric collectReqs(M, MAI, MMI, *ST); 1068bdd1243dSDimitry Andric 1069fcaf7f86SDimitry Andric // Process type/const/global var/func decl instructions, number their 107081ad6265SDimitry Andric // destination registers from 0 to N, collect Extensions and Capabilities. 1071753f127fSDimitry Andric processDefInstrs(M); 107281ad6265SDimitry Andric 107381ad6265SDimitry Andric // Number rest of registers from N+1 onwards. 107481ad6265SDimitry Andric numberRegistersGlobally(M); 107581ad6265SDimitry Andric 107681ad6265SDimitry Andric // Collect OpName, OpEntryPoint, OpDecorate etc, process other instructions. 107781ad6265SDimitry Andric processOtherInstrs(M); 107881ad6265SDimitry Andric 1079bdd1243dSDimitry Andric // If there are no entry points, we need the Linkage capability. 1080bdd1243dSDimitry Andric if (MAI.MS[SPIRV::MB_EntryPoints].empty()) 1081bdd1243dSDimitry Andric MAI.Reqs.addCapability(SPIRV::Capability::Linkage); 1082bdd1243dSDimitry Andric 108381ad6265SDimitry Andric return false; 108481ad6265SDimitry Andric } 1085