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 266fcaf7f86SDimitry Andric // True if there is an instruction in the MS list with all the same operands as 267fcaf7f86SDimitry Andric // the given instruction has (after the given starting index). 268fcaf7f86SDimitry Andric // TODO: maybe it needs to check Opcodes too. 269fcaf7f86SDimitry Andric static bool findSameInstrInMS(const MachineInstr &A, 270fcaf7f86SDimitry Andric SPIRV::ModuleSectionType MSType, 271fcaf7f86SDimitry Andric SPIRV::ModuleAnalysisInfo &MAI, 272fcaf7f86SDimitry Andric unsigned StartOpIndex = 0) { 273fcaf7f86SDimitry Andric for (const auto *B : MAI.MS[MSType]) { 274fcaf7f86SDimitry Andric const unsigned NumAOps = A.getNumOperands(); 275fcaf7f86SDimitry Andric if (NumAOps != B->getNumOperands() || A.getNumDefs() != B->getNumDefs()) 276fcaf7f86SDimitry Andric continue; 277fcaf7f86SDimitry Andric bool AllOpsMatch = true; 278fcaf7f86SDimitry Andric for (unsigned i = StartOpIndex; i < NumAOps && AllOpsMatch; ++i) { 279fcaf7f86SDimitry Andric if (A.getOperand(i).isReg() && B->getOperand(i).isReg()) { 280fcaf7f86SDimitry Andric Register RegA = A.getOperand(i).getReg(); 281fcaf7f86SDimitry Andric Register RegB = B->getOperand(i).getReg(); 282fcaf7f86SDimitry Andric AllOpsMatch = MAI.getRegisterAlias(A.getMF(), RegA) == 283fcaf7f86SDimitry Andric MAI.getRegisterAlias(B->getMF(), RegB); 284fcaf7f86SDimitry Andric } else { 285fcaf7f86SDimitry Andric AllOpsMatch = A.getOperand(i).isIdenticalTo(B->getOperand(i)); 286fcaf7f86SDimitry Andric } 287fcaf7f86SDimitry Andric } 288fcaf7f86SDimitry Andric if (AllOpsMatch) 289fcaf7f86SDimitry Andric return true; 290fcaf7f86SDimitry Andric } 291fcaf7f86SDimitry Andric return false; 292fcaf7f86SDimitry Andric } 293fcaf7f86SDimitry Andric 294bdd1243dSDimitry Andric // Look for IDs declared with Import linkage, and map the corresponding function 29581ad6265SDimitry Andric // to the register defining that variable (which will usually be the result of 29681ad6265SDimitry Andric // an OpFunction). This lets us call externally imported functions using 29781ad6265SDimitry Andric // the correct ID registers. 29881ad6265SDimitry Andric void SPIRVModuleAnalysis::collectFuncNames(MachineInstr &MI, 299bdd1243dSDimitry Andric const Function *F) { 30081ad6265SDimitry Andric if (MI.getOpcode() == SPIRV::OpDecorate) { 30181ad6265SDimitry Andric // If it's got Import linkage. 30281ad6265SDimitry Andric auto Dec = MI.getOperand(1).getImm(); 30381ad6265SDimitry Andric if (Dec == static_cast<unsigned>(SPIRV::Decoration::LinkageAttributes)) { 30481ad6265SDimitry Andric auto Lnk = MI.getOperand(MI.getNumOperands() - 1).getImm(); 30581ad6265SDimitry Andric if (Lnk == static_cast<unsigned>(SPIRV::LinkageType::Import)) { 30681ad6265SDimitry Andric // Map imported function name to function ID register. 307bdd1243dSDimitry Andric const Function *ImportedFunc = 308bdd1243dSDimitry Andric F->getParent()->getFunction(getStringImm(MI, 2)); 30981ad6265SDimitry Andric Register Target = MI.getOperand(0).getReg(); 310bdd1243dSDimitry Andric MAI.FuncMap[ImportedFunc] = MAI.getRegisterAlias(MI.getMF(), Target); 31181ad6265SDimitry Andric } 31281ad6265SDimitry Andric } 31381ad6265SDimitry Andric } else if (MI.getOpcode() == SPIRV::OpFunction) { 31481ad6265SDimitry Andric // Record all internal OpFunction declarations. 31581ad6265SDimitry Andric Register Reg = MI.defs().begin()->getReg(); 31681ad6265SDimitry Andric Register GlobalReg = MAI.getRegisterAlias(MI.getMF(), Reg); 31781ad6265SDimitry Andric assert(GlobalReg.isValid()); 318bdd1243dSDimitry Andric MAI.FuncMap[F] = GlobalReg; 31981ad6265SDimitry Andric } 32081ad6265SDimitry Andric } 32181ad6265SDimitry Andric 32281ad6265SDimitry Andric // Collect the given instruction in the specified MS. We assume global register 32381ad6265SDimitry Andric // numbering has already occurred by this point. We can directly compare reg 32481ad6265SDimitry Andric // arguments when detecting duplicates. 32581ad6265SDimitry Andric static void collectOtherInstr(MachineInstr &MI, SPIRV::ModuleAnalysisInfo &MAI, 326fcaf7f86SDimitry Andric SPIRV::ModuleSectionType MSType, 327fcaf7f86SDimitry Andric bool Append = true) { 32881ad6265SDimitry Andric MAI.setSkipEmission(&MI); 329fcaf7f86SDimitry Andric if (findSameInstrInMS(MI, MSType, MAI)) 33081ad6265SDimitry Andric return; // Found a duplicate, so don't add it. 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) { 34181ad6265SDimitry Andric for (auto F = M.begin(), E = M.end(); F != E; ++F) { 34281ad6265SDimitry Andric if ((*F).isDeclaration()) 34381ad6265SDimitry Andric continue; 34481ad6265SDimitry Andric MachineFunction *MF = MMI->getMachineFunction(*F); 34581ad6265SDimitry Andric assert(MF); 34681ad6265SDimitry Andric for (MachineBasicBlock &MBB : *MF) 34781ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 34881ad6265SDimitry Andric if (MAI.getSkipEmission(&MI)) 34981ad6265SDimitry Andric continue; 35081ad6265SDimitry Andric const unsigned OpCode = MI.getOpcode(); 35181ad6265SDimitry Andric if (OpCode == SPIRV::OpName || OpCode == SPIRV::OpMemberName) { 35281ad6265SDimitry Andric collectOtherInstr(MI, MAI, SPIRV::MB_DebugNames); 35381ad6265SDimitry Andric } else if (OpCode == SPIRV::OpEntryPoint) { 35481ad6265SDimitry Andric collectOtherInstr(MI, MAI, SPIRV::MB_EntryPoints); 35581ad6265SDimitry Andric } else if (TII->isDecorationInstr(MI)) { 35681ad6265SDimitry Andric collectOtherInstr(MI, MAI, SPIRV::MB_Annotations); 357bdd1243dSDimitry Andric collectFuncNames(MI, &*F); 358fcaf7f86SDimitry Andric } else if (TII->isConstantInstr(MI)) { 359fcaf7f86SDimitry Andric // Now OpSpecConstant*s are not in DT, 360fcaf7f86SDimitry Andric // but they need to be collected anyway. 361fcaf7f86SDimitry Andric collectOtherInstr(MI, MAI, SPIRV::MB_TypeConstVars); 36281ad6265SDimitry Andric } else if (OpCode == SPIRV::OpFunction) { 363bdd1243dSDimitry Andric collectFuncNames(MI, &*F); 364fcaf7f86SDimitry Andric } else if (OpCode == SPIRV::OpTypeForwardPointer) { 365fcaf7f86SDimitry Andric collectOtherInstr(MI, MAI, SPIRV::MB_TypeConstVars, false); 36681ad6265SDimitry Andric } 36781ad6265SDimitry Andric } 36881ad6265SDimitry Andric } 36981ad6265SDimitry Andric } 37081ad6265SDimitry Andric 37181ad6265SDimitry Andric // Number registers in all functions globally from 0 onwards and store 372fcaf7f86SDimitry Andric // the result in global register alias table. Some registers are already 373fcaf7f86SDimitry Andric // numbered in collectGlobalEntities. 37481ad6265SDimitry Andric void SPIRVModuleAnalysis::numberRegistersGlobally(const Module &M) { 37581ad6265SDimitry Andric for (auto F = M.begin(), E = M.end(); F != E; ++F) { 37681ad6265SDimitry Andric if ((*F).isDeclaration()) 37781ad6265SDimitry Andric continue; 37881ad6265SDimitry Andric MachineFunction *MF = MMI->getMachineFunction(*F); 37981ad6265SDimitry Andric assert(MF); 38081ad6265SDimitry Andric for (MachineBasicBlock &MBB : *MF) { 38181ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 38281ad6265SDimitry Andric for (MachineOperand &Op : MI.operands()) { 38381ad6265SDimitry Andric if (!Op.isReg()) 38481ad6265SDimitry Andric continue; 38581ad6265SDimitry Andric Register Reg = Op.getReg(); 38681ad6265SDimitry Andric if (MAI.hasRegisterAlias(MF, Reg)) 38781ad6265SDimitry Andric continue; 38881ad6265SDimitry Andric Register NewReg = Register::index2VirtReg(MAI.getNextID()); 38981ad6265SDimitry Andric MAI.setRegisterAlias(MF, Reg, NewReg); 39081ad6265SDimitry Andric } 391fcaf7f86SDimitry Andric if (MI.getOpcode() != SPIRV::OpExtInst) 392fcaf7f86SDimitry Andric continue; 393fcaf7f86SDimitry Andric auto Set = MI.getOperand(2).getImm(); 394*cb14a3feSDimitry Andric if (!MAI.ExtInstSetMap.contains(Set)) 395fcaf7f86SDimitry Andric MAI.ExtInstSetMap[Set] = Register::index2VirtReg(MAI.getNextID()); 39681ad6265SDimitry Andric } 39781ad6265SDimitry Andric } 39881ad6265SDimitry Andric } 39981ad6265SDimitry Andric } 40081ad6265SDimitry Andric 401bdd1243dSDimitry Andric // RequirementHandler implementations. 402bdd1243dSDimitry Andric void SPIRV::RequirementHandler::getAndAddRequirements( 403bdd1243dSDimitry Andric SPIRV::OperandCategory::OperandCategory Category, uint32_t i, 404bdd1243dSDimitry Andric const SPIRVSubtarget &ST) { 405bdd1243dSDimitry Andric addRequirements(getSymbolicOperandRequirements(Category, i, ST, *this)); 406bdd1243dSDimitry Andric } 407bdd1243dSDimitry Andric 408bdd1243dSDimitry Andric void SPIRV::RequirementHandler::pruneCapabilities( 409bdd1243dSDimitry Andric const CapabilityList &ToPrune) { 410bdd1243dSDimitry Andric for (const auto &Cap : ToPrune) { 411bdd1243dSDimitry Andric AllCaps.insert(Cap); 412bdd1243dSDimitry Andric auto FoundIndex = std::find(MinimalCaps.begin(), MinimalCaps.end(), Cap); 413bdd1243dSDimitry Andric if (FoundIndex != MinimalCaps.end()) 414bdd1243dSDimitry Andric MinimalCaps.erase(FoundIndex); 415bdd1243dSDimitry Andric CapabilityList ImplicitDecls = 416bdd1243dSDimitry Andric getSymbolicOperandCapabilities(OperandCategory::CapabilityOperand, Cap); 417bdd1243dSDimitry Andric pruneCapabilities(ImplicitDecls); 418bdd1243dSDimitry Andric } 419bdd1243dSDimitry Andric } 420bdd1243dSDimitry Andric 421bdd1243dSDimitry Andric void SPIRV::RequirementHandler::addCapabilities(const CapabilityList &ToAdd) { 422bdd1243dSDimitry Andric for (const auto &Cap : ToAdd) { 423bdd1243dSDimitry Andric bool IsNewlyInserted = AllCaps.insert(Cap).second; 424bdd1243dSDimitry Andric if (!IsNewlyInserted) // Don't re-add if it's already been declared. 425bdd1243dSDimitry Andric continue; 426bdd1243dSDimitry Andric CapabilityList ImplicitDecls = 427bdd1243dSDimitry Andric getSymbolicOperandCapabilities(OperandCategory::CapabilityOperand, Cap); 428bdd1243dSDimitry Andric pruneCapabilities(ImplicitDecls); 429bdd1243dSDimitry Andric MinimalCaps.push_back(Cap); 430bdd1243dSDimitry Andric } 431bdd1243dSDimitry Andric } 432bdd1243dSDimitry Andric 433bdd1243dSDimitry Andric void SPIRV::RequirementHandler::addRequirements( 434bdd1243dSDimitry Andric const SPIRV::Requirements &Req) { 435bdd1243dSDimitry Andric if (!Req.IsSatisfiable) 436bdd1243dSDimitry Andric report_fatal_error("Adding SPIR-V requirements this target can't satisfy."); 437bdd1243dSDimitry Andric 438bdd1243dSDimitry Andric if (Req.Cap.has_value()) 439bdd1243dSDimitry Andric addCapabilities({Req.Cap.value()}); 440bdd1243dSDimitry Andric 441bdd1243dSDimitry Andric addExtensions(Req.Exts); 442bdd1243dSDimitry Andric 443bdd1243dSDimitry Andric if (Req.MinVer) { 444bdd1243dSDimitry Andric if (MaxVersion && Req.MinVer > MaxVersion) { 445bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Conflicting version requirements: >= " << Req.MinVer 446bdd1243dSDimitry Andric << " and <= " << MaxVersion << "\n"); 447bdd1243dSDimitry Andric report_fatal_error("Adding SPIR-V requirements that can't be satisfied."); 448bdd1243dSDimitry Andric } 449bdd1243dSDimitry Andric 450bdd1243dSDimitry Andric if (MinVersion == 0 || Req.MinVer > MinVersion) 451bdd1243dSDimitry Andric MinVersion = Req.MinVer; 452bdd1243dSDimitry Andric } 453bdd1243dSDimitry Andric 454bdd1243dSDimitry Andric if (Req.MaxVer) { 455bdd1243dSDimitry Andric if (MinVersion && Req.MaxVer < MinVersion) { 456bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Conflicting version requirements: <= " << Req.MaxVer 457bdd1243dSDimitry Andric << " and >= " << MinVersion << "\n"); 458bdd1243dSDimitry Andric report_fatal_error("Adding SPIR-V requirements that can't be satisfied."); 459bdd1243dSDimitry Andric } 460bdd1243dSDimitry Andric 461bdd1243dSDimitry Andric if (MaxVersion == 0 || Req.MaxVer < MaxVersion) 462bdd1243dSDimitry Andric MaxVersion = Req.MaxVer; 463bdd1243dSDimitry Andric } 464bdd1243dSDimitry Andric } 465bdd1243dSDimitry Andric 466bdd1243dSDimitry Andric void SPIRV::RequirementHandler::checkSatisfiable( 467bdd1243dSDimitry Andric const SPIRVSubtarget &ST) const { 468bdd1243dSDimitry Andric // Report as many errors as possible before aborting the compilation. 469bdd1243dSDimitry Andric bool IsSatisfiable = true; 470bdd1243dSDimitry Andric auto TargetVer = ST.getSPIRVVersion(); 471bdd1243dSDimitry Andric 472bdd1243dSDimitry Andric if (MaxVersion && TargetVer && MaxVersion < TargetVer) { 473bdd1243dSDimitry Andric LLVM_DEBUG( 474bdd1243dSDimitry Andric dbgs() << "Target SPIR-V version too high for required features\n" 475bdd1243dSDimitry Andric << "Required max version: " << MaxVersion << " target version " 476bdd1243dSDimitry Andric << TargetVer << "\n"); 477bdd1243dSDimitry Andric IsSatisfiable = false; 478bdd1243dSDimitry Andric } 479bdd1243dSDimitry Andric 480bdd1243dSDimitry Andric if (MinVersion && TargetVer && MinVersion > TargetVer) { 481bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Target SPIR-V version too low for required features\n" 482bdd1243dSDimitry Andric << "Required min version: " << MinVersion 483bdd1243dSDimitry Andric << " target version " << TargetVer << "\n"); 484bdd1243dSDimitry Andric IsSatisfiable = false; 485bdd1243dSDimitry Andric } 486bdd1243dSDimitry Andric 487bdd1243dSDimitry Andric if (MinVersion && MaxVersion && MinVersion > MaxVersion) { 488bdd1243dSDimitry Andric LLVM_DEBUG( 489bdd1243dSDimitry Andric dbgs() 490bdd1243dSDimitry Andric << "Version is too low for some features and too high for others.\n" 491bdd1243dSDimitry Andric << "Required SPIR-V min version: " << MinVersion 492bdd1243dSDimitry Andric << " required SPIR-V max version " << MaxVersion << "\n"); 493bdd1243dSDimitry Andric IsSatisfiable = false; 494bdd1243dSDimitry Andric } 495bdd1243dSDimitry Andric 496bdd1243dSDimitry Andric for (auto Cap : MinimalCaps) { 497bdd1243dSDimitry Andric if (AvailableCaps.contains(Cap)) 498bdd1243dSDimitry Andric continue; 499bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Capability not supported: " 500bdd1243dSDimitry Andric << getSymbolicOperandMnemonic( 501bdd1243dSDimitry Andric OperandCategory::CapabilityOperand, Cap) 502bdd1243dSDimitry Andric << "\n"); 503bdd1243dSDimitry Andric IsSatisfiable = false; 504bdd1243dSDimitry Andric } 505bdd1243dSDimitry Andric 506bdd1243dSDimitry Andric for (auto Ext : AllExtensions) { 507bdd1243dSDimitry Andric if (ST.canUseExtension(Ext)) 508bdd1243dSDimitry Andric continue; 5095f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Extension not supported: " 510bdd1243dSDimitry Andric << getSymbolicOperandMnemonic( 511bdd1243dSDimitry Andric OperandCategory::ExtensionOperand, Ext) 512bdd1243dSDimitry Andric << "\n"); 513bdd1243dSDimitry Andric IsSatisfiable = false; 514bdd1243dSDimitry Andric } 515bdd1243dSDimitry Andric 516bdd1243dSDimitry Andric if (!IsSatisfiable) 517bdd1243dSDimitry Andric report_fatal_error("Unable to meet SPIR-V requirements for this target."); 518bdd1243dSDimitry Andric } 519bdd1243dSDimitry Andric 520bdd1243dSDimitry Andric // Add the given capabilities and all their implicitly defined capabilities too. 521bdd1243dSDimitry Andric void SPIRV::RequirementHandler::addAvailableCaps(const CapabilityList &ToAdd) { 522bdd1243dSDimitry Andric for (const auto Cap : ToAdd) 523bdd1243dSDimitry Andric if (AvailableCaps.insert(Cap).second) 524bdd1243dSDimitry Andric addAvailableCaps(getSymbolicOperandCapabilities( 525bdd1243dSDimitry Andric SPIRV::OperandCategory::CapabilityOperand, Cap)); 526bdd1243dSDimitry Andric } 527bdd1243dSDimitry Andric 5285f757f3fSDimitry Andric void SPIRV::RequirementHandler::removeCapabilityIf( 5295f757f3fSDimitry Andric const Capability::Capability ToRemove, 5305f757f3fSDimitry Andric const Capability::Capability IfPresent) { 5315f757f3fSDimitry Andric if (AllCaps.contains(IfPresent)) 5325f757f3fSDimitry Andric AllCaps.erase(ToRemove); 5335f757f3fSDimitry Andric } 5345f757f3fSDimitry Andric 535bdd1243dSDimitry Andric namespace llvm { 536bdd1243dSDimitry Andric namespace SPIRV { 537bdd1243dSDimitry Andric void RequirementHandler::initAvailableCapabilities(const SPIRVSubtarget &ST) { 5385f757f3fSDimitry Andric if (ST.isOpenCLEnv()) { 5395f757f3fSDimitry Andric initAvailableCapabilitiesForOpenCL(ST); 540bdd1243dSDimitry Andric return; 5415f757f3fSDimitry Andric } 5425f757f3fSDimitry Andric 5435f757f3fSDimitry Andric if (ST.isVulkanEnv()) { 5445f757f3fSDimitry Andric initAvailableCapabilitiesForVulkan(ST); 5455f757f3fSDimitry Andric return; 5465f757f3fSDimitry Andric } 5475f757f3fSDimitry Andric 5485f757f3fSDimitry Andric report_fatal_error("Unimplemented environment for SPIR-V generation."); 5495f757f3fSDimitry Andric } 5505f757f3fSDimitry Andric 5515f757f3fSDimitry Andric void RequirementHandler::initAvailableCapabilitiesForOpenCL( 5525f757f3fSDimitry Andric const SPIRVSubtarget &ST) { 553bdd1243dSDimitry Andric // Add the min requirements for different OpenCL and SPIR-V versions. 554bdd1243dSDimitry Andric addAvailableCaps({Capability::Addresses, Capability::Float16Buffer, 555bdd1243dSDimitry Andric Capability::Int16, Capability::Int8, Capability::Kernel, 556bdd1243dSDimitry Andric Capability::Linkage, Capability::Vector16, 557bdd1243dSDimitry Andric Capability::Groups, Capability::GenericPointer, 558bdd1243dSDimitry Andric Capability::Shader}); 559bdd1243dSDimitry Andric if (ST.hasOpenCLFullProfile()) 560bdd1243dSDimitry Andric addAvailableCaps({Capability::Int64, Capability::Int64Atomics}); 561bdd1243dSDimitry Andric if (ST.hasOpenCLImageSupport()) { 562bdd1243dSDimitry Andric addAvailableCaps({Capability::ImageBasic, Capability::LiteralSampler, 563bdd1243dSDimitry Andric Capability::Image1D, Capability::SampledBuffer, 564bdd1243dSDimitry Andric Capability::ImageBuffer}); 565bdd1243dSDimitry Andric if (ST.isAtLeastOpenCLVer(20)) 566bdd1243dSDimitry Andric addAvailableCaps({Capability::ImageReadWrite}); 567bdd1243dSDimitry Andric } 568bdd1243dSDimitry Andric if (ST.isAtLeastSPIRVVer(11) && ST.isAtLeastOpenCLVer(22)) 569bdd1243dSDimitry Andric addAvailableCaps({Capability::SubgroupDispatch, Capability::PipeStorage}); 570bdd1243dSDimitry Andric if (ST.isAtLeastSPIRVVer(13)) 571bdd1243dSDimitry Andric addAvailableCaps({Capability::GroupNonUniform, 572bdd1243dSDimitry Andric Capability::GroupNonUniformVote, 573bdd1243dSDimitry Andric Capability::GroupNonUniformArithmetic, 574bdd1243dSDimitry Andric Capability::GroupNonUniformBallot, 575bdd1243dSDimitry Andric Capability::GroupNonUniformClustered, 576bdd1243dSDimitry Andric Capability::GroupNonUniformShuffle, 577bdd1243dSDimitry Andric Capability::GroupNonUniformShuffleRelative}); 578bdd1243dSDimitry Andric if (ST.isAtLeastSPIRVVer(14)) 579bdd1243dSDimitry Andric addAvailableCaps({Capability::DenormPreserve, Capability::DenormFlushToZero, 580bdd1243dSDimitry Andric Capability::SignedZeroInfNanPreserve, 581bdd1243dSDimitry Andric Capability::RoundingModeRTE, 582bdd1243dSDimitry Andric Capability::RoundingModeRTZ}); 583bdd1243dSDimitry Andric // TODO: verify if this needs some checks. 584bdd1243dSDimitry Andric addAvailableCaps({Capability::Float16, Capability::Float64}); 585bdd1243dSDimitry Andric 5865f757f3fSDimitry Andric // Add capabilities enabled by extensions. 5875f757f3fSDimitry Andric for (auto Extension : ST.getAllAvailableExtensions()) { 5885f757f3fSDimitry Andric CapabilityList EnabledCapabilities = 5895f757f3fSDimitry Andric getCapabilitiesEnabledByExtension(Extension); 5905f757f3fSDimitry Andric addAvailableCaps(EnabledCapabilities); 5915f757f3fSDimitry Andric } 5925f757f3fSDimitry Andric 593bdd1243dSDimitry Andric // TODO: add OpenCL extensions. 594bdd1243dSDimitry Andric } 5955f757f3fSDimitry Andric 5965f757f3fSDimitry Andric void RequirementHandler::initAvailableCapabilitiesForVulkan( 5975f757f3fSDimitry Andric const SPIRVSubtarget &ST) { 5985f757f3fSDimitry Andric addAvailableCaps({Capability::Shader, Capability::Linkage}); 5995f757f3fSDimitry Andric 6005f757f3fSDimitry Andric // Provided by Vulkan version 1.0. 6015f757f3fSDimitry Andric addAvailableCaps({Capability::Int16, Capability::Int64, Capability::Float64}); 6025f757f3fSDimitry Andric } 6035f757f3fSDimitry Andric 604bdd1243dSDimitry Andric } // namespace SPIRV 605bdd1243dSDimitry Andric } // namespace llvm 606bdd1243dSDimitry Andric 607bdd1243dSDimitry Andric // Add the required capabilities from a decoration instruction (including 608bdd1243dSDimitry Andric // BuiltIns). 609bdd1243dSDimitry Andric static void addOpDecorateReqs(const MachineInstr &MI, unsigned DecIndex, 610bdd1243dSDimitry Andric SPIRV::RequirementHandler &Reqs, 611bdd1243dSDimitry Andric const SPIRVSubtarget &ST) { 612bdd1243dSDimitry Andric int64_t DecOp = MI.getOperand(DecIndex).getImm(); 613bdd1243dSDimitry Andric auto Dec = static_cast<SPIRV::Decoration::Decoration>(DecOp); 614bdd1243dSDimitry Andric Reqs.addRequirements(getSymbolicOperandRequirements( 615bdd1243dSDimitry Andric SPIRV::OperandCategory::DecorationOperand, Dec, ST, Reqs)); 616bdd1243dSDimitry Andric 617bdd1243dSDimitry Andric if (Dec == SPIRV::Decoration::BuiltIn) { 618bdd1243dSDimitry Andric int64_t BuiltInOp = MI.getOperand(DecIndex + 1).getImm(); 619bdd1243dSDimitry Andric auto BuiltIn = static_cast<SPIRV::BuiltIn::BuiltIn>(BuiltInOp); 620bdd1243dSDimitry Andric Reqs.addRequirements(getSymbolicOperandRequirements( 621bdd1243dSDimitry Andric SPIRV::OperandCategory::BuiltInOperand, BuiltIn, ST, Reqs)); 622bdd1243dSDimitry Andric } 623bdd1243dSDimitry Andric } 624bdd1243dSDimitry Andric 625bdd1243dSDimitry Andric // Add requirements for image handling. 626bdd1243dSDimitry Andric static void addOpTypeImageReqs(const MachineInstr &MI, 627bdd1243dSDimitry Andric SPIRV::RequirementHandler &Reqs, 628bdd1243dSDimitry Andric const SPIRVSubtarget &ST) { 629bdd1243dSDimitry Andric assert(MI.getNumOperands() >= 8 && "Insufficient operands for OpTypeImage"); 630bdd1243dSDimitry Andric // The operand indices used here are based on the OpTypeImage layout, which 631bdd1243dSDimitry Andric // the MachineInstr follows as well. 632bdd1243dSDimitry Andric int64_t ImgFormatOp = MI.getOperand(7).getImm(); 633bdd1243dSDimitry Andric auto ImgFormat = static_cast<SPIRV::ImageFormat::ImageFormat>(ImgFormatOp); 634bdd1243dSDimitry Andric Reqs.getAndAddRequirements(SPIRV::OperandCategory::ImageFormatOperand, 635bdd1243dSDimitry Andric ImgFormat, ST); 636bdd1243dSDimitry Andric 637bdd1243dSDimitry Andric bool IsArrayed = MI.getOperand(4).getImm() == 1; 638bdd1243dSDimitry Andric bool IsMultisampled = MI.getOperand(5).getImm() == 1; 639bdd1243dSDimitry Andric bool NoSampler = MI.getOperand(6).getImm() == 2; 640bdd1243dSDimitry Andric // Add dimension requirements. 641bdd1243dSDimitry Andric assert(MI.getOperand(2).isImm()); 642bdd1243dSDimitry Andric switch (MI.getOperand(2).getImm()) { 643bdd1243dSDimitry Andric case SPIRV::Dim::DIM_1D: 644bdd1243dSDimitry Andric Reqs.addRequirements(NoSampler ? SPIRV::Capability::Image1D 645bdd1243dSDimitry Andric : SPIRV::Capability::Sampled1D); 646bdd1243dSDimitry Andric break; 647bdd1243dSDimitry Andric case SPIRV::Dim::DIM_2D: 648bdd1243dSDimitry Andric if (IsMultisampled && NoSampler) 649bdd1243dSDimitry Andric Reqs.addRequirements(SPIRV::Capability::ImageMSArray); 650bdd1243dSDimitry Andric break; 651bdd1243dSDimitry Andric case SPIRV::Dim::DIM_Cube: 652bdd1243dSDimitry Andric Reqs.addRequirements(SPIRV::Capability::Shader); 653bdd1243dSDimitry Andric if (IsArrayed) 654bdd1243dSDimitry Andric Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageCubeArray 655bdd1243dSDimitry Andric : SPIRV::Capability::SampledCubeArray); 656bdd1243dSDimitry Andric break; 657bdd1243dSDimitry Andric case SPIRV::Dim::DIM_Rect: 658bdd1243dSDimitry Andric Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageRect 659bdd1243dSDimitry Andric : SPIRV::Capability::SampledRect); 660bdd1243dSDimitry Andric break; 661bdd1243dSDimitry Andric case SPIRV::Dim::DIM_Buffer: 662bdd1243dSDimitry Andric Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageBuffer 663bdd1243dSDimitry Andric : SPIRV::Capability::SampledBuffer); 664bdd1243dSDimitry Andric break; 665bdd1243dSDimitry Andric case SPIRV::Dim::DIM_SubpassData: 666bdd1243dSDimitry Andric Reqs.addRequirements(SPIRV::Capability::InputAttachment); 667bdd1243dSDimitry Andric break; 668bdd1243dSDimitry Andric } 669bdd1243dSDimitry Andric 670bdd1243dSDimitry Andric // Has optional access qualifier. 671bdd1243dSDimitry Andric // TODO: check if it's OpenCL's kernel. 672bdd1243dSDimitry Andric if (MI.getNumOperands() > 8 && 673bdd1243dSDimitry Andric MI.getOperand(8).getImm() == SPIRV::AccessQualifier::ReadWrite) 674bdd1243dSDimitry Andric Reqs.addRequirements(SPIRV::Capability::ImageReadWrite); 675bdd1243dSDimitry Andric else 676bdd1243dSDimitry Andric Reqs.addRequirements(SPIRV::Capability::ImageBasic); 677bdd1243dSDimitry Andric } 678bdd1243dSDimitry Andric 679bdd1243dSDimitry Andric void addInstrRequirements(const MachineInstr &MI, 680bdd1243dSDimitry Andric SPIRV::RequirementHandler &Reqs, 681bdd1243dSDimitry Andric const SPIRVSubtarget &ST) { 682bdd1243dSDimitry Andric switch (MI.getOpcode()) { 683bdd1243dSDimitry Andric case SPIRV::OpMemoryModel: { 684bdd1243dSDimitry Andric int64_t Addr = MI.getOperand(0).getImm(); 685bdd1243dSDimitry Andric Reqs.getAndAddRequirements(SPIRV::OperandCategory::AddressingModelOperand, 686bdd1243dSDimitry Andric Addr, ST); 687bdd1243dSDimitry Andric int64_t Mem = MI.getOperand(1).getImm(); 688bdd1243dSDimitry Andric Reqs.getAndAddRequirements(SPIRV::OperandCategory::MemoryModelOperand, Mem, 689bdd1243dSDimitry Andric ST); 690bdd1243dSDimitry Andric break; 691bdd1243dSDimitry Andric } 692bdd1243dSDimitry Andric case SPIRV::OpEntryPoint: { 693bdd1243dSDimitry Andric int64_t Exe = MI.getOperand(0).getImm(); 694bdd1243dSDimitry Andric Reqs.getAndAddRequirements(SPIRV::OperandCategory::ExecutionModelOperand, 695bdd1243dSDimitry Andric Exe, ST); 696bdd1243dSDimitry Andric break; 697bdd1243dSDimitry Andric } 698bdd1243dSDimitry Andric case SPIRV::OpExecutionMode: 699bdd1243dSDimitry Andric case SPIRV::OpExecutionModeId: { 700bdd1243dSDimitry Andric int64_t Exe = MI.getOperand(1).getImm(); 701bdd1243dSDimitry Andric Reqs.getAndAddRequirements(SPIRV::OperandCategory::ExecutionModeOperand, 702bdd1243dSDimitry Andric Exe, ST); 703bdd1243dSDimitry Andric break; 704bdd1243dSDimitry Andric } 705bdd1243dSDimitry Andric case SPIRV::OpTypeMatrix: 706bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Matrix); 707bdd1243dSDimitry Andric break; 708bdd1243dSDimitry Andric case SPIRV::OpTypeInt: { 709bdd1243dSDimitry Andric unsigned BitWidth = MI.getOperand(1).getImm(); 710bdd1243dSDimitry Andric if (BitWidth == 64) 711bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Int64); 712bdd1243dSDimitry Andric else if (BitWidth == 16) 713bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Int16); 714bdd1243dSDimitry Andric else if (BitWidth == 8) 715bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Int8); 716bdd1243dSDimitry Andric break; 717bdd1243dSDimitry Andric } 718bdd1243dSDimitry Andric case SPIRV::OpTypeFloat: { 719bdd1243dSDimitry Andric unsigned BitWidth = MI.getOperand(1).getImm(); 720bdd1243dSDimitry Andric if (BitWidth == 64) 721bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Float64); 722bdd1243dSDimitry Andric else if (BitWidth == 16) 723bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Float16); 724bdd1243dSDimitry Andric break; 725bdd1243dSDimitry Andric } 726bdd1243dSDimitry Andric case SPIRV::OpTypeVector: { 727bdd1243dSDimitry Andric unsigned NumComponents = MI.getOperand(2).getImm(); 728bdd1243dSDimitry Andric if (NumComponents == 8 || NumComponents == 16) 729bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Vector16); 730bdd1243dSDimitry Andric break; 731bdd1243dSDimitry Andric } 732bdd1243dSDimitry Andric case SPIRV::OpTypePointer: { 733bdd1243dSDimitry Andric auto SC = MI.getOperand(1).getImm(); 734bdd1243dSDimitry Andric Reqs.getAndAddRequirements(SPIRV::OperandCategory::StorageClassOperand, SC, 735bdd1243dSDimitry Andric ST); 736bdd1243dSDimitry Andric // If it's a type of pointer to float16, add Float16Buffer capability. 737bdd1243dSDimitry Andric assert(MI.getOperand(2).isReg()); 738bdd1243dSDimitry Andric const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo(); 739bdd1243dSDimitry Andric SPIRVType *TypeDef = MRI.getVRegDef(MI.getOperand(2).getReg()); 740bdd1243dSDimitry Andric if (TypeDef->getOpcode() == SPIRV::OpTypeFloat && 741bdd1243dSDimitry Andric TypeDef->getOperand(1).getImm() == 16) 742bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Float16Buffer); 743bdd1243dSDimitry Andric break; 744bdd1243dSDimitry Andric } 745bdd1243dSDimitry Andric case SPIRV::OpBitReverse: 7465f757f3fSDimitry Andric case SPIRV::OpBitFieldInsert: 7475f757f3fSDimitry Andric case SPIRV::OpBitFieldSExtract: 7485f757f3fSDimitry Andric case SPIRV::OpBitFieldUExtract: 7495f757f3fSDimitry Andric if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions)) { 7505f757f3fSDimitry Andric Reqs.addCapability(SPIRV::Capability::Shader); 7515f757f3fSDimitry Andric break; 7525f757f3fSDimitry Andric } 7535f757f3fSDimitry Andric Reqs.addExtension(SPIRV::Extension::SPV_KHR_bit_instructions); 7545f757f3fSDimitry Andric Reqs.addCapability(SPIRV::Capability::BitInstructions); 7555f757f3fSDimitry Andric break; 756bdd1243dSDimitry Andric case SPIRV::OpTypeRuntimeArray: 757bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Shader); 758bdd1243dSDimitry Andric break; 759bdd1243dSDimitry Andric case SPIRV::OpTypeOpaque: 760bdd1243dSDimitry Andric case SPIRV::OpTypeEvent: 761bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Kernel); 762bdd1243dSDimitry Andric break; 763bdd1243dSDimitry Andric case SPIRV::OpTypePipe: 764bdd1243dSDimitry Andric case SPIRV::OpTypeReserveId: 765bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Pipes); 766bdd1243dSDimitry Andric break; 767bdd1243dSDimitry Andric case SPIRV::OpTypeDeviceEvent: 768bdd1243dSDimitry Andric case SPIRV::OpTypeQueue: 769bdd1243dSDimitry Andric case SPIRV::OpBuildNDRange: 770bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::DeviceEnqueue); 771bdd1243dSDimitry Andric break; 772bdd1243dSDimitry Andric case SPIRV::OpDecorate: 773bdd1243dSDimitry Andric case SPIRV::OpDecorateId: 774bdd1243dSDimitry Andric case SPIRV::OpDecorateString: 775bdd1243dSDimitry Andric addOpDecorateReqs(MI, 1, Reqs, ST); 776bdd1243dSDimitry Andric break; 777bdd1243dSDimitry Andric case SPIRV::OpMemberDecorate: 778bdd1243dSDimitry Andric case SPIRV::OpMemberDecorateString: 779bdd1243dSDimitry Andric addOpDecorateReqs(MI, 2, Reqs, ST); 780bdd1243dSDimitry Andric break; 781bdd1243dSDimitry Andric case SPIRV::OpInBoundsPtrAccessChain: 782bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Addresses); 783bdd1243dSDimitry Andric break; 784bdd1243dSDimitry Andric case SPIRV::OpConstantSampler: 785bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::LiteralSampler); 786bdd1243dSDimitry Andric break; 787bdd1243dSDimitry Andric case SPIRV::OpTypeImage: 788bdd1243dSDimitry Andric addOpTypeImageReqs(MI, Reqs, ST); 789bdd1243dSDimitry Andric break; 790bdd1243dSDimitry Andric case SPIRV::OpTypeSampler: 791bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::ImageBasic); 792bdd1243dSDimitry Andric break; 793bdd1243dSDimitry Andric case SPIRV::OpTypeForwardPointer: 794bdd1243dSDimitry Andric // TODO: check if it's OpenCL's kernel. 795bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Addresses); 796bdd1243dSDimitry Andric break; 797bdd1243dSDimitry Andric case SPIRV::OpAtomicFlagTestAndSet: 798bdd1243dSDimitry Andric case SPIRV::OpAtomicLoad: 799bdd1243dSDimitry Andric case SPIRV::OpAtomicStore: 800bdd1243dSDimitry Andric case SPIRV::OpAtomicExchange: 801bdd1243dSDimitry Andric case SPIRV::OpAtomicCompareExchange: 802bdd1243dSDimitry Andric case SPIRV::OpAtomicIIncrement: 803bdd1243dSDimitry Andric case SPIRV::OpAtomicIDecrement: 804bdd1243dSDimitry Andric case SPIRV::OpAtomicIAdd: 805bdd1243dSDimitry Andric case SPIRV::OpAtomicISub: 806bdd1243dSDimitry Andric case SPIRV::OpAtomicUMin: 807bdd1243dSDimitry Andric case SPIRV::OpAtomicUMax: 808bdd1243dSDimitry Andric case SPIRV::OpAtomicSMin: 809bdd1243dSDimitry Andric case SPIRV::OpAtomicSMax: 810bdd1243dSDimitry Andric case SPIRV::OpAtomicAnd: 811bdd1243dSDimitry Andric case SPIRV::OpAtomicOr: 812bdd1243dSDimitry Andric case SPIRV::OpAtomicXor: { 813bdd1243dSDimitry Andric const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo(); 814bdd1243dSDimitry Andric const MachineInstr *InstrPtr = &MI; 815bdd1243dSDimitry Andric if (MI.getOpcode() == SPIRV::OpAtomicStore) { 816bdd1243dSDimitry Andric assert(MI.getOperand(3).isReg()); 817bdd1243dSDimitry Andric InstrPtr = MRI.getVRegDef(MI.getOperand(3).getReg()); 818bdd1243dSDimitry Andric assert(InstrPtr && "Unexpected type instruction for OpAtomicStore"); 819bdd1243dSDimitry Andric } 820bdd1243dSDimitry Andric assert(InstrPtr->getOperand(1).isReg() && "Unexpected operand in atomic"); 821bdd1243dSDimitry Andric Register TypeReg = InstrPtr->getOperand(1).getReg(); 822bdd1243dSDimitry Andric SPIRVType *TypeDef = MRI.getVRegDef(TypeReg); 823bdd1243dSDimitry Andric if (TypeDef->getOpcode() == SPIRV::OpTypeInt) { 824bdd1243dSDimitry Andric unsigned BitWidth = TypeDef->getOperand(1).getImm(); 825bdd1243dSDimitry Andric if (BitWidth == 64) 826bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Int64Atomics); 827bdd1243dSDimitry Andric } 828bdd1243dSDimitry Andric break; 829bdd1243dSDimitry Andric } 830bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformIAdd: 831bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformFAdd: 832bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformIMul: 833bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformFMul: 834bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformSMin: 835bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformUMin: 836bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformFMin: 837bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformSMax: 838bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformUMax: 839bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformFMax: 840bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformBitwiseAnd: 841bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformBitwiseOr: 842bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformBitwiseXor: 843bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformLogicalAnd: 844bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformLogicalOr: 845bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformLogicalXor: { 846bdd1243dSDimitry Andric assert(MI.getOperand(3).isImm()); 847bdd1243dSDimitry Andric int64_t GroupOp = MI.getOperand(3).getImm(); 848bdd1243dSDimitry Andric switch (GroupOp) { 849bdd1243dSDimitry Andric case SPIRV::GroupOperation::Reduce: 850bdd1243dSDimitry Andric case SPIRV::GroupOperation::InclusiveScan: 851bdd1243dSDimitry Andric case SPIRV::GroupOperation::ExclusiveScan: 852bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Kernel); 853bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::GroupNonUniformArithmetic); 854bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::GroupNonUniformBallot); 855bdd1243dSDimitry Andric break; 856bdd1243dSDimitry Andric case SPIRV::GroupOperation::ClusteredReduce: 857bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::GroupNonUniformClustered); 858bdd1243dSDimitry Andric break; 859bdd1243dSDimitry Andric case SPIRV::GroupOperation::PartitionedReduceNV: 860bdd1243dSDimitry Andric case SPIRV::GroupOperation::PartitionedInclusiveScanNV: 861bdd1243dSDimitry Andric case SPIRV::GroupOperation::PartitionedExclusiveScanNV: 862bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::GroupNonUniformPartitionedNV); 863bdd1243dSDimitry Andric break; 864bdd1243dSDimitry Andric } 865bdd1243dSDimitry Andric break; 866bdd1243dSDimitry Andric } 867bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformShuffle: 868bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformShuffleXor: 869bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::GroupNonUniformShuffle); 870bdd1243dSDimitry Andric break; 871bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformShuffleUp: 872bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformShuffleDown: 873bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::GroupNonUniformShuffleRelative); 874bdd1243dSDimitry Andric break; 875bdd1243dSDimitry Andric case SPIRV::OpGroupAll: 876bdd1243dSDimitry Andric case SPIRV::OpGroupAny: 877bdd1243dSDimitry Andric case SPIRV::OpGroupBroadcast: 878bdd1243dSDimitry Andric case SPIRV::OpGroupIAdd: 879bdd1243dSDimitry Andric case SPIRV::OpGroupFAdd: 880bdd1243dSDimitry Andric case SPIRV::OpGroupFMin: 881bdd1243dSDimitry Andric case SPIRV::OpGroupUMin: 882bdd1243dSDimitry Andric case SPIRV::OpGroupSMin: 883bdd1243dSDimitry Andric case SPIRV::OpGroupFMax: 884bdd1243dSDimitry Andric case SPIRV::OpGroupUMax: 885bdd1243dSDimitry Andric case SPIRV::OpGroupSMax: 886bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::Groups); 887bdd1243dSDimitry Andric break; 888bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformElect: 889bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::GroupNonUniform); 890bdd1243dSDimitry Andric break; 891bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformAll: 892bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformAny: 893bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformAllEqual: 894bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::GroupNonUniformVote); 895bdd1243dSDimitry Andric break; 896bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformBroadcast: 897bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformBroadcastFirst: 898bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformBallot: 899bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformInverseBallot: 900bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformBallotBitExtract: 901bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformBallotBitCount: 902bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformBallotFindLSB: 903bdd1243dSDimitry Andric case SPIRV::OpGroupNonUniformBallotFindMSB: 904bdd1243dSDimitry Andric Reqs.addCapability(SPIRV::Capability::GroupNonUniformBallot); 905bdd1243dSDimitry Andric break; 9065f757f3fSDimitry Andric case SPIRV::OpAssumeTrueKHR: 9075f757f3fSDimitry Andric case SPIRV::OpExpectKHR: 9085f757f3fSDimitry Andric if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) { 9095f757f3fSDimitry Andric Reqs.addExtension(SPIRV::Extension::SPV_KHR_expect_assume); 9105f757f3fSDimitry Andric Reqs.addCapability(SPIRV::Capability::ExpectAssumeKHR); 9115f757f3fSDimitry Andric } 9125f757f3fSDimitry Andric break; 913bdd1243dSDimitry Andric default: 914bdd1243dSDimitry Andric break; 915bdd1243dSDimitry Andric } 9165f757f3fSDimitry Andric 9175f757f3fSDimitry Andric // If we require capability Shader, then we can remove the requirement for 9185f757f3fSDimitry Andric // the BitInstructions capability, since Shader is a superset capability 9195f757f3fSDimitry Andric // of BitInstructions. 9205f757f3fSDimitry Andric Reqs.removeCapabilityIf(SPIRV::Capability::BitInstructions, 9215f757f3fSDimitry Andric SPIRV::Capability::Shader); 922bdd1243dSDimitry Andric } 923bdd1243dSDimitry Andric 924bdd1243dSDimitry Andric static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI, 925bdd1243dSDimitry Andric MachineModuleInfo *MMI, const SPIRVSubtarget &ST) { 926bdd1243dSDimitry Andric // Collect requirements for existing instructions. 927bdd1243dSDimitry Andric for (auto F = M.begin(), E = M.end(); F != E; ++F) { 928bdd1243dSDimitry Andric MachineFunction *MF = MMI->getMachineFunction(*F); 929bdd1243dSDimitry Andric if (!MF) 930bdd1243dSDimitry Andric continue; 931bdd1243dSDimitry Andric for (const MachineBasicBlock &MBB : *MF) 932bdd1243dSDimitry Andric for (const MachineInstr &MI : MBB) 933bdd1243dSDimitry Andric addInstrRequirements(MI, MAI.Reqs, ST); 934bdd1243dSDimitry Andric } 935bdd1243dSDimitry Andric // Collect requirements for OpExecutionMode instructions. 936bdd1243dSDimitry Andric auto Node = M.getNamedMetadata("spirv.ExecutionMode"); 937bdd1243dSDimitry Andric if (Node) { 938bdd1243dSDimitry Andric for (unsigned i = 0; i < Node->getNumOperands(); i++) { 939bdd1243dSDimitry Andric MDNode *MDN = cast<MDNode>(Node->getOperand(i)); 940bdd1243dSDimitry Andric const MDOperand &MDOp = MDN->getOperand(1); 941bdd1243dSDimitry Andric if (auto *CMeta = dyn_cast<ConstantAsMetadata>(MDOp)) { 942bdd1243dSDimitry Andric Constant *C = CMeta->getValue(); 943bdd1243dSDimitry Andric if (ConstantInt *Const = dyn_cast<ConstantInt>(C)) { 944bdd1243dSDimitry Andric auto EM = Const->getZExtValue(); 945bdd1243dSDimitry Andric MAI.Reqs.getAndAddRequirements( 946bdd1243dSDimitry Andric SPIRV::OperandCategory::ExecutionModeOperand, EM, ST); 947bdd1243dSDimitry Andric } 948bdd1243dSDimitry Andric } 949bdd1243dSDimitry Andric } 950bdd1243dSDimitry Andric } 951bdd1243dSDimitry Andric for (auto FI = M.begin(), E = M.end(); FI != E; ++FI) { 952bdd1243dSDimitry Andric const Function &F = *FI; 953bdd1243dSDimitry Andric if (F.isDeclaration()) 954bdd1243dSDimitry Andric continue; 955bdd1243dSDimitry Andric if (F.getMetadata("reqd_work_group_size")) 956bdd1243dSDimitry Andric MAI.Reqs.getAndAddRequirements( 957bdd1243dSDimitry Andric SPIRV::OperandCategory::ExecutionModeOperand, 958bdd1243dSDimitry Andric SPIRV::ExecutionMode::LocalSize, ST); 9595f757f3fSDimitry Andric if (F.getFnAttribute("hlsl.numthreads").isValid()) { 9605f757f3fSDimitry Andric MAI.Reqs.getAndAddRequirements( 9615f757f3fSDimitry Andric SPIRV::OperandCategory::ExecutionModeOperand, 9625f757f3fSDimitry Andric SPIRV::ExecutionMode::LocalSize, ST); 9635f757f3fSDimitry Andric } 964bdd1243dSDimitry Andric if (F.getMetadata("work_group_size_hint")) 965bdd1243dSDimitry Andric MAI.Reqs.getAndAddRequirements( 966bdd1243dSDimitry Andric SPIRV::OperandCategory::ExecutionModeOperand, 967bdd1243dSDimitry Andric SPIRV::ExecutionMode::LocalSizeHint, ST); 968bdd1243dSDimitry Andric if (F.getMetadata("intel_reqd_sub_group_size")) 969bdd1243dSDimitry Andric MAI.Reqs.getAndAddRequirements( 970bdd1243dSDimitry Andric SPIRV::OperandCategory::ExecutionModeOperand, 971bdd1243dSDimitry Andric SPIRV::ExecutionMode::SubgroupSize, ST); 972bdd1243dSDimitry Andric if (F.getMetadata("vec_type_hint")) 973bdd1243dSDimitry Andric MAI.Reqs.getAndAddRequirements( 974bdd1243dSDimitry Andric SPIRV::OperandCategory::ExecutionModeOperand, 975bdd1243dSDimitry Andric SPIRV::ExecutionMode::VecTypeHint, ST); 9765f757f3fSDimitry Andric 9775f757f3fSDimitry Andric if (F.hasOptNone() && 9785f757f3fSDimitry Andric ST.canUseExtension(SPIRV::Extension::SPV_INTEL_optnone)) { 9795f757f3fSDimitry Andric // Output OpCapability OptNoneINTEL. 9805f757f3fSDimitry Andric MAI.Reqs.addExtension(SPIRV::Extension::SPV_INTEL_optnone); 9815f757f3fSDimitry Andric MAI.Reqs.addCapability(SPIRV::Capability::OptNoneINTEL); 9825f757f3fSDimitry Andric } 983bdd1243dSDimitry Andric } 984bdd1243dSDimitry Andric } 985bdd1243dSDimitry Andric 986bdd1243dSDimitry Andric static unsigned getFastMathFlags(const MachineInstr &I) { 987bdd1243dSDimitry Andric unsigned Flags = SPIRV::FPFastMathMode::None; 988bdd1243dSDimitry Andric if (I.getFlag(MachineInstr::MIFlag::FmNoNans)) 989bdd1243dSDimitry Andric Flags |= SPIRV::FPFastMathMode::NotNaN; 990bdd1243dSDimitry Andric if (I.getFlag(MachineInstr::MIFlag::FmNoInfs)) 991bdd1243dSDimitry Andric Flags |= SPIRV::FPFastMathMode::NotInf; 992bdd1243dSDimitry Andric if (I.getFlag(MachineInstr::MIFlag::FmNsz)) 993bdd1243dSDimitry Andric Flags |= SPIRV::FPFastMathMode::NSZ; 994bdd1243dSDimitry Andric if (I.getFlag(MachineInstr::MIFlag::FmArcp)) 995bdd1243dSDimitry Andric Flags |= SPIRV::FPFastMathMode::AllowRecip; 996bdd1243dSDimitry Andric if (I.getFlag(MachineInstr::MIFlag::FmReassoc)) 997bdd1243dSDimitry Andric Flags |= SPIRV::FPFastMathMode::Fast; 998bdd1243dSDimitry Andric return Flags; 999bdd1243dSDimitry Andric } 1000bdd1243dSDimitry Andric 1001bdd1243dSDimitry Andric static void handleMIFlagDecoration(MachineInstr &I, const SPIRVSubtarget &ST, 1002bdd1243dSDimitry Andric const SPIRVInstrInfo &TII, 1003bdd1243dSDimitry Andric SPIRV::RequirementHandler &Reqs) { 1004bdd1243dSDimitry Andric if (I.getFlag(MachineInstr::MIFlag::NoSWrap) && TII.canUseNSW(I) && 1005bdd1243dSDimitry Andric getSymbolicOperandRequirements(SPIRV::OperandCategory::DecorationOperand, 1006bdd1243dSDimitry Andric SPIRV::Decoration::NoSignedWrap, ST, Reqs) 1007bdd1243dSDimitry Andric .IsSatisfiable) { 1008bdd1243dSDimitry Andric buildOpDecorate(I.getOperand(0).getReg(), I, TII, 1009bdd1243dSDimitry Andric SPIRV::Decoration::NoSignedWrap, {}); 1010bdd1243dSDimitry Andric } 1011bdd1243dSDimitry Andric if (I.getFlag(MachineInstr::MIFlag::NoUWrap) && TII.canUseNUW(I) && 1012bdd1243dSDimitry Andric getSymbolicOperandRequirements(SPIRV::OperandCategory::DecorationOperand, 1013bdd1243dSDimitry Andric SPIRV::Decoration::NoUnsignedWrap, ST, 1014bdd1243dSDimitry Andric Reqs) 1015bdd1243dSDimitry Andric .IsSatisfiable) { 1016bdd1243dSDimitry Andric buildOpDecorate(I.getOperand(0).getReg(), I, TII, 1017bdd1243dSDimitry Andric SPIRV::Decoration::NoUnsignedWrap, {}); 1018bdd1243dSDimitry Andric } 1019bdd1243dSDimitry Andric if (!TII.canUseFastMathFlags(I)) 1020bdd1243dSDimitry Andric return; 1021bdd1243dSDimitry Andric unsigned FMFlags = getFastMathFlags(I); 1022bdd1243dSDimitry Andric if (FMFlags == SPIRV::FPFastMathMode::None) 1023bdd1243dSDimitry Andric return; 1024bdd1243dSDimitry Andric Register DstReg = I.getOperand(0).getReg(); 1025bdd1243dSDimitry Andric buildOpDecorate(DstReg, I, TII, SPIRV::Decoration::FPFastMathMode, {FMFlags}); 1026bdd1243dSDimitry Andric } 1027bdd1243dSDimitry Andric 1028bdd1243dSDimitry Andric // Walk all functions and add decorations related to MI flags. 1029bdd1243dSDimitry Andric static void addDecorations(const Module &M, const SPIRVInstrInfo &TII, 1030bdd1243dSDimitry Andric MachineModuleInfo *MMI, const SPIRVSubtarget &ST, 1031bdd1243dSDimitry Andric SPIRV::ModuleAnalysisInfo &MAI) { 1032bdd1243dSDimitry Andric for (auto F = M.begin(), E = M.end(); F != E; ++F) { 1033bdd1243dSDimitry Andric MachineFunction *MF = MMI->getMachineFunction(*F); 1034bdd1243dSDimitry Andric if (!MF) 1035bdd1243dSDimitry Andric continue; 1036bdd1243dSDimitry Andric for (auto &MBB : *MF) 1037bdd1243dSDimitry Andric for (auto &MI : MBB) 1038bdd1243dSDimitry Andric handleMIFlagDecoration(MI, ST, TII, MAI.Reqs); 1039bdd1243dSDimitry Andric } 1040bdd1243dSDimitry Andric } 1041bdd1243dSDimitry Andric 104281ad6265SDimitry Andric struct SPIRV::ModuleAnalysisInfo SPIRVModuleAnalysis::MAI; 104381ad6265SDimitry Andric 104481ad6265SDimitry Andric void SPIRVModuleAnalysis::getAnalysisUsage(AnalysisUsage &AU) const { 104581ad6265SDimitry Andric AU.addRequired<TargetPassConfig>(); 104681ad6265SDimitry Andric AU.addRequired<MachineModuleInfoWrapperPass>(); 104781ad6265SDimitry Andric } 104881ad6265SDimitry Andric 104981ad6265SDimitry Andric bool SPIRVModuleAnalysis::runOnModule(Module &M) { 105081ad6265SDimitry Andric SPIRVTargetMachine &TM = 105181ad6265SDimitry Andric getAnalysis<TargetPassConfig>().getTM<SPIRVTargetMachine>(); 105281ad6265SDimitry Andric ST = TM.getSubtargetImpl(); 105381ad6265SDimitry Andric GR = ST->getSPIRVGlobalRegistry(); 105481ad6265SDimitry Andric TII = ST->getInstrInfo(); 105581ad6265SDimitry Andric 105681ad6265SDimitry Andric MMI = &getAnalysis<MachineModuleInfoWrapperPass>().getMMI(); 105781ad6265SDimitry Andric 105881ad6265SDimitry Andric setBaseInfo(M); 105981ad6265SDimitry Andric 1060bdd1243dSDimitry Andric addDecorations(M, *TII, MMI, *ST, MAI); 1061bdd1243dSDimitry Andric 1062bdd1243dSDimitry Andric collectReqs(M, MAI, MMI, *ST); 1063bdd1243dSDimitry Andric 1064fcaf7f86SDimitry Andric // Process type/const/global var/func decl instructions, number their 106581ad6265SDimitry Andric // destination registers from 0 to N, collect Extensions and Capabilities. 1066753f127fSDimitry Andric processDefInstrs(M); 106781ad6265SDimitry Andric 106881ad6265SDimitry Andric // Number rest of registers from N+1 onwards. 106981ad6265SDimitry Andric numberRegistersGlobally(M); 107081ad6265SDimitry Andric 107181ad6265SDimitry Andric // Collect OpName, OpEntryPoint, OpDecorate etc, process other instructions. 107281ad6265SDimitry Andric processOtherInstrs(M); 107381ad6265SDimitry Andric 1074bdd1243dSDimitry Andric // If there are no entry points, we need the Linkage capability. 1075bdd1243dSDimitry Andric if (MAI.MS[SPIRV::MB_EntryPoints].empty()) 1076bdd1243dSDimitry Andric MAI.Reqs.addCapability(SPIRV::Capability::Linkage); 1077bdd1243dSDimitry Andric 107881ad6265SDimitry Andric return false; 107981ad6265SDimitry Andric } 1080