xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
38*0fca6ea1SDimitry Andric static cl::list<SPIRV::Capability::Capability>
39*0fca6ea1SDimitry Andric     AvoidCapabilities("avoid-spirv-capabilities",
40*0fca6ea1SDimitry Andric                       cl::desc("SPIR-V capabilities to avoid if there are "
41*0fca6ea1SDimitry Andric                                "other options enabling a feature"),
42*0fca6ea1SDimitry Andric                       cl::ZeroOrMore, cl::Hidden,
43*0fca6ea1SDimitry Andric                       cl::values(clEnumValN(SPIRV::Capability::Shader, "Shader",
44*0fca6ea1SDimitry Andric                                             "SPIR-V Shader capability")));
45*0fca6ea1SDimitry Andric // Use sets instead of cl::list to check "if contains" condition
46*0fca6ea1SDimitry Andric struct AvoidCapabilitiesSet {
47*0fca6ea1SDimitry Andric   SmallSet<SPIRV::Capability::Capability, 4> S;
48*0fca6ea1SDimitry Andric   AvoidCapabilitiesSet() {
49*0fca6ea1SDimitry Andric     for (auto Cap : AvoidCapabilities)
50*0fca6ea1SDimitry Andric       S.insert(Cap);
51*0fca6ea1SDimitry Andric   }
52*0fca6ea1SDimitry Andric };
53*0fca6ea1SDimitry Andric 
5481ad6265SDimitry Andric char llvm::SPIRVModuleAnalysis::ID = 0;
5581ad6265SDimitry Andric 
5681ad6265SDimitry Andric namespace llvm {
5781ad6265SDimitry Andric void initializeSPIRVModuleAnalysisPass(PassRegistry &);
5881ad6265SDimitry Andric } // namespace llvm
5981ad6265SDimitry Andric 
6081ad6265SDimitry Andric INITIALIZE_PASS(SPIRVModuleAnalysis, DEBUG_TYPE, "SPIRV module analysis", true,
6181ad6265SDimitry Andric                 true)
6281ad6265SDimitry Andric 
6381ad6265SDimitry Andric // Retrieve an unsigned from an MDNode with a list of them as operands.
6481ad6265SDimitry Andric static unsigned getMetadataUInt(MDNode *MdNode, unsigned OpIndex,
6581ad6265SDimitry Andric                                 unsigned DefaultVal = 0) {
6681ad6265SDimitry Andric   if (MdNode && OpIndex < MdNode->getNumOperands()) {
6781ad6265SDimitry Andric     const auto &Op = MdNode->getOperand(OpIndex);
6881ad6265SDimitry Andric     return mdconst::extract<ConstantInt>(Op)->getZExtValue();
6981ad6265SDimitry Andric   }
7081ad6265SDimitry Andric   return DefaultVal;
7181ad6265SDimitry Andric }
7281ad6265SDimitry Andric 
73bdd1243dSDimitry Andric static SPIRV::Requirements
74bdd1243dSDimitry Andric getSymbolicOperandRequirements(SPIRV::OperandCategory::OperandCategory Category,
75bdd1243dSDimitry Andric                                unsigned i, const SPIRVSubtarget &ST,
76bdd1243dSDimitry Andric                                SPIRV::RequirementHandler &Reqs) {
77*0fca6ea1SDimitry Andric   static AvoidCapabilitiesSet
78*0fca6ea1SDimitry Andric       AvoidCaps; // contains capabilities to avoid if there is another option
79*0fca6ea1SDimitry Andric 
80*0fca6ea1SDimitry Andric   VersionTuple ReqMinVer = getSymbolicOperandMinVersion(Category, i);
81*0fca6ea1SDimitry Andric   VersionTuple ReqMaxVer = getSymbolicOperandMaxVersion(Category, i);
82*0fca6ea1SDimitry Andric   VersionTuple SPIRVVersion = ST.getSPIRVVersion();
83*0fca6ea1SDimitry Andric   bool MinVerOK = SPIRVVersion.empty() || SPIRVVersion >= ReqMinVer;
84*0fca6ea1SDimitry Andric   bool MaxVerOK =
85*0fca6ea1SDimitry Andric       ReqMaxVer.empty() || SPIRVVersion.empty() || SPIRVVersion <= ReqMaxVer;
86bdd1243dSDimitry Andric   CapabilityList ReqCaps = getSymbolicOperandCapabilities(Category, i);
87bdd1243dSDimitry Andric   ExtensionList ReqExts = getSymbolicOperandExtensions(Category, i);
88bdd1243dSDimitry Andric   if (ReqCaps.empty()) {
89bdd1243dSDimitry Andric     if (ReqExts.empty()) {
90bdd1243dSDimitry Andric       if (MinVerOK && MaxVerOK)
91bdd1243dSDimitry Andric         return {true, {}, {}, ReqMinVer, ReqMaxVer};
92*0fca6ea1SDimitry Andric       return {false, {}, {}, VersionTuple(), VersionTuple()};
93bdd1243dSDimitry Andric     }
94bdd1243dSDimitry Andric   } else if (MinVerOK && MaxVerOK) {
95*0fca6ea1SDimitry Andric     if (ReqCaps.size() == 1) {
96*0fca6ea1SDimitry Andric       auto Cap = ReqCaps[0];
97bdd1243dSDimitry Andric       if (Reqs.isCapabilityAvailable(Cap))
98*0fca6ea1SDimitry Andric         return {true, {Cap}, ReqExts, ReqMinVer, ReqMaxVer};
99*0fca6ea1SDimitry Andric     } else {
100*0fca6ea1SDimitry Andric       // By SPIR-V specification: "If an instruction, enumerant, or other
101*0fca6ea1SDimitry Andric       // feature specifies multiple enabling capabilities, only one such
102*0fca6ea1SDimitry Andric       // capability needs to be declared to use the feature." However, one
103*0fca6ea1SDimitry Andric       // capability may be preferred over another. We use command line
104*0fca6ea1SDimitry Andric       // argument(s) and AvoidCapabilities to avoid selection of certain
105*0fca6ea1SDimitry Andric       // capabilities if there are other options.
106*0fca6ea1SDimitry Andric       CapabilityList UseCaps;
107*0fca6ea1SDimitry Andric       for (auto Cap : ReqCaps)
108*0fca6ea1SDimitry Andric         if (Reqs.isCapabilityAvailable(Cap))
109*0fca6ea1SDimitry Andric           UseCaps.push_back(Cap);
110*0fca6ea1SDimitry Andric       for (size_t i = 0, Sz = UseCaps.size(); i < Sz; ++i) {
111*0fca6ea1SDimitry Andric         auto Cap = UseCaps[i];
112*0fca6ea1SDimitry Andric         if (i == Sz - 1 || !AvoidCaps.S.contains(Cap))
113*0fca6ea1SDimitry Andric           return {true, {Cap}, ReqExts, ReqMinVer, ReqMaxVer};
114*0fca6ea1SDimitry Andric       }
115bdd1243dSDimitry Andric     }
116bdd1243dSDimitry Andric   }
117bdd1243dSDimitry Andric   // If there are no capabilities, or we can't satisfy the version or
118bdd1243dSDimitry Andric   // capability requirements, use the list of extensions (if the subtarget
119bdd1243dSDimitry Andric   // can handle them all).
120bdd1243dSDimitry Andric   if (llvm::all_of(ReqExts, [&ST](const SPIRV::Extension::Extension &Ext) {
121bdd1243dSDimitry Andric         return ST.canUseExtension(Ext);
122bdd1243dSDimitry Andric       })) {
123*0fca6ea1SDimitry Andric     return {true,
124*0fca6ea1SDimitry Andric             {},
125*0fca6ea1SDimitry Andric             ReqExts,
126*0fca6ea1SDimitry Andric             VersionTuple(),
127*0fca6ea1SDimitry Andric             VersionTuple()}; // TODO: add versions to extensions.
128bdd1243dSDimitry Andric   }
129*0fca6ea1SDimitry Andric   return {false, {}, {}, VersionTuple(), VersionTuple()};
130bdd1243dSDimitry Andric }
131bdd1243dSDimitry Andric 
13281ad6265SDimitry Andric void SPIRVModuleAnalysis::setBaseInfo(const Module &M) {
13381ad6265SDimitry Andric   MAI.MaxID = 0;
13481ad6265SDimitry Andric   for (int i = 0; i < SPIRV::NUM_MODULE_SECTIONS; i++)
13581ad6265SDimitry Andric     MAI.MS[i].clear();
13681ad6265SDimitry Andric   MAI.RegisterAliasTable.clear();
13781ad6265SDimitry Andric   MAI.InstrsToDelete.clear();
138bdd1243dSDimitry Andric   MAI.FuncMap.clear();
13981ad6265SDimitry Andric   MAI.GlobalVarList.clear();
140fcaf7f86SDimitry Andric   MAI.ExtInstSetMap.clear();
141bdd1243dSDimitry Andric   MAI.Reqs.clear();
142bdd1243dSDimitry Andric   MAI.Reqs.initAvailableCapabilities(*ST);
14381ad6265SDimitry Andric 
14481ad6265SDimitry Andric   // TODO: determine memory model and source language from the configuratoin.
145fcaf7f86SDimitry Andric   if (auto MemModel = M.getNamedMetadata("spirv.MemoryModel")) {
146fcaf7f86SDimitry Andric     auto MemMD = MemModel->getOperand(0);
147bdd1243dSDimitry Andric     MAI.Addr = static_cast<SPIRV::AddressingModel::AddressingModel>(
148bdd1243dSDimitry Andric         getMetadataUInt(MemMD, 0));
149bdd1243dSDimitry Andric     MAI.Mem =
150bdd1243dSDimitry Andric         static_cast<SPIRV::MemoryModel::MemoryModel>(getMetadataUInt(MemMD, 1));
151fcaf7f86SDimitry Andric   } else {
1525f757f3fSDimitry Andric     // TODO: Add support for VulkanMemoryModel.
1535f757f3fSDimitry Andric     MAI.Mem = ST->isOpenCLEnv() ? SPIRV::MemoryModel::OpenCL
1545f757f3fSDimitry Andric                                 : SPIRV::MemoryModel::GLSL450;
1555f757f3fSDimitry Andric     if (MAI.Mem == SPIRV::MemoryModel::OpenCL) {
15681ad6265SDimitry Andric       unsigned PtrSize = ST->getPointerSize();
15781ad6265SDimitry Andric       MAI.Addr = PtrSize == 32   ? SPIRV::AddressingModel::Physical32
15881ad6265SDimitry Andric                  : PtrSize == 64 ? SPIRV::AddressingModel::Physical64
15981ad6265SDimitry Andric                                  : SPIRV::AddressingModel::Logical;
1605f757f3fSDimitry Andric     } else {
1615f757f3fSDimitry Andric       // TODO: Add support for PhysicalStorageBufferAddress.
1625f757f3fSDimitry Andric       MAI.Addr = SPIRV::AddressingModel::Logical;
1635f757f3fSDimitry Andric     }
164fcaf7f86SDimitry Andric   }
16581ad6265SDimitry Andric   // Get the OpenCL version number from metadata.
16681ad6265SDimitry Andric   // TODO: support other source languages.
16781ad6265SDimitry Andric   if (auto VerNode = M.getNamedMetadata("opencl.ocl.version")) {
168fcaf7f86SDimitry Andric     MAI.SrcLang = SPIRV::SourceLanguage::OpenCL_C;
169fcaf7f86SDimitry Andric     // Construct version literal in accordance with SPIRV-LLVM-Translator.
170fcaf7f86SDimitry Andric     // TODO: support multiple OCL version metadata.
171fcaf7f86SDimitry Andric     assert(VerNode->getNumOperands() > 0 && "Invalid SPIR");
17281ad6265SDimitry Andric     auto VersionMD = VerNode->getOperand(0);
17381ad6265SDimitry Andric     unsigned MajorNum = getMetadataUInt(VersionMD, 0, 2);
17481ad6265SDimitry Andric     unsigned MinorNum = getMetadataUInt(VersionMD, 1);
17581ad6265SDimitry Andric     unsigned RevNum = getMetadataUInt(VersionMD, 2);
176*0fca6ea1SDimitry Andric     // Prevent Major part of OpenCL version to be 0
177*0fca6ea1SDimitry Andric     MAI.SrcLangVersion =
178*0fca6ea1SDimitry Andric         (std::max(1U, MajorNum) * 100 + MinorNum) * 1000 + RevNum;
179*0fca6ea1SDimitry Andric   } else {
180*0fca6ea1SDimitry Andric     // If there is no information about OpenCL version we are forced to generate
181*0fca6ea1SDimitry Andric     // OpenCL 1.0 by default for the OpenCL environment to avoid puzzling
182*0fca6ea1SDimitry Andric     // run-times with Unknown/0.0 version output. For a reference, LLVM-SPIRV
183*0fca6ea1SDimitry Andric     // Translator avoids potential issues with run-times in a similar manner.
184*0fca6ea1SDimitry Andric     if (ST->isOpenCLEnv()) {
185*0fca6ea1SDimitry Andric       MAI.SrcLang = SPIRV::SourceLanguage::OpenCL_CPP;
186*0fca6ea1SDimitry Andric       MAI.SrcLangVersion = 100000;
187fcaf7f86SDimitry Andric     } else {
188fcaf7f86SDimitry Andric       MAI.SrcLang = SPIRV::SourceLanguage::Unknown;
189fcaf7f86SDimitry Andric       MAI.SrcLangVersion = 0;
190fcaf7f86SDimitry Andric     }
191*0fca6ea1SDimitry Andric   }
192fcaf7f86SDimitry Andric 
193fcaf7f86SDimitry Andric   if (auto ExtNode = M.getNamedMetadata("opencl.used.extensions")) {
194fcaf7f86SDimitry Andric     for (unsigned I = 0, E = ExtNode->getNumOperands(); I != E; ++I) {
195fcaf7f86SDimitry Andric       MDNode *MD = ExtNode->getOperand(I);
196fcaf7f86SDimitry Andric       if (!MD || MD->getNumOperands() == 0)
197fcaf7f86SDimitry Andric         continue;
198fcaf7f86SDimitry Andric       for (unsigned J = 0, N = MD->getNumOperands(); J != N; ++J)
199fcaf7f86SDimitry Andric         MAI.SrcExt.insert(cast<MDString>(MD->getOperand(J))->getString());
20081ad6265SDimitry Andric     }
20181ad6265SDimitry Andric   }
20281ad6265SDimitry Andric 
203bdd1243dSDimitry Andric   // Update required capabilities for this memory model, addressing model and
204bdd1243dSDimitry Andric   // source language.
205bdd1243dSDimitry Andric   MAI.Reqs.getAndAddRequirements(SPIRV::OperandCategory::MemoryModelOperand,
206bdd1243dSDimitry Andric                                  MAI.Mem, *ST);
207bdd1243dSDimitry Andric   MAI.Reqs.getAndAddRequirements(SPIRV::OperandCategory::SourceLanguageOperand,
208bdd1243dSDimitry Andric                                  MAI.SrcLang, *ST);
209bdd1243dSDimitry Andric   MAI.Reqs.getAndAddRequirements(SPIRV::OperandCategory::AddressingModelOperand,
210bdd1243dSDimitry Andric                                  MAI.Addr, *ST);
211bdd1243dSDimitry Andric 
2125f757f3fSDimitry Andric   if (ST->isOpenCLEnv()) {
213fcaf7f86SDimitry Andric     // TODO: check if it's required by default.
2145f757f3fSDimitry Andric     MAI.ExtInstSetMap[static_cast<unsigned>(
2155f757f3fSDimitry Andric         SPIRV::InstructionSet::OpenCL_std)] =
216fcaf7f86SDimitry Andric         Register::index2VirtReg(MAI.getNextID());
21781ad6265SDimitry Andric   }
2185f757f3fSDimitry Andric }
21981ad6265SDimitry Andric 
220753f127fSDimitry Andric // Collect MI which defines the register in the given machine function.
221753f127fSDimitry Andric static void collectDefInstr(Register Reg, const MachineFunction *MF,
222753f127fSDimitry Andric                             SPIRV::ModuleAnalysisInfo *MAI,
223753f127fSDimitry Andric                             SPIRV::ModuleSectionType MSType,
224753f127fSDimitry Andric                             bool DoInsert = true) {
225753f127fSDimitry Andric   assert(MAI->hasRegisterAlias(MF, Reg) && "Cannot find register alias");
226753f127fSDimitry Andric   MachineInstr *MI = MF->getRegInfo().getUniqueVRegDef(Reg);
227753f127fSDimitry Andric   assert(MI && "There should be an instruction that defines the register");
228753f127fSDimitry Andric   MAI->setSkipEmission(MI);
229753f127fSDimitry Andric   if (DoInsert)
230753f127fSDimitry Andric     MAI->MS[MSType].push_back(MI);
231753f127fSDimitry Andric }
232753f127fSDimitry Andric 
233753f127fSDimitry Andric void SPIRVModuleAnalysis::collectGlobalEntities(
234753f127fSDimitry Andric     const std::vector<SPIRV::DTSortableEntry *> &DepsGraph,
235753f127fSDimitry Andric     SPIRV::ModuleSectionType MSType,
236753f127fSDimitry Andric     std::function<bool(const SPIRV::DTSortableEntry *)> Pred,
237fcaf7f86SDimitry Andric     bool UsePreOrder = false) {
238753f127fSDimitry Andric   DenseSet<const SPIRV::DTSortableEntry *> Visited;
239753f127fSDimitry Andric   for (const auto *E : DepsGraph) {
240753f127fSDimitry Andric     std::function<void(const SPIRV::DTSortableEntry *)> RecHoistUtil;
241753f127fSDimitry Andric     // NOTE: here we prefer recursive approach over iterative because
242753f127fSDimitry Andric     // we don't expect depchains long enough to cause SO.
243753f127fSDimitry Andric     RecHoistUtil = [MSType, UsePreOrder, &Visited, &Pred,
244753f127fSDimitry Andric                     &RecHoistUtil](const SPIRV::DTSortableEntry *E) {
245753f127fSDimitry Andric       if (Visited.count(E) || !Pred(E))
246753f127fSDimitry Andric         return;
247753f127fSDimitry Andric       Visited.insert(E);
248753f127fSDimitry Andric 
249753f127fSDimitry Andric       // Traversing deps graph in post-order allows us to get rid of
250753f127fSDimitry Andric       // register aliases preprocessing.
251753f127fSDimitry Andric       // But pre-order is required for correct processing of function
252753f127fSDimitry Andric       // declaration and arguments processing.
253753f127fSDimitry Andric       if (!UsePreOrder)
254753f127fSDimitry Andric         for (auto *S : E->getDeps())
255753f127fSDimitry Andric           RecHoistUtil(S);
256753f127fSDimitry Andric 
257753f127fSDimitry Andric       Register GlobalReg = Register::index2VirtReg(MAI.getNextID());
258753f127fSDimitry Andric       bool IsFirst = true;
259753f127fSDimitry Andric       for (auto &U : *E) {
260753f127fSDimitry Andric         const MachineFunction *MF = U.first;
261753f127fSDimitry Andric         Register Reg = U.second;
262753f127fSDimitry Andric         MAI.setRegisterAlias(MF, Reg, GlobalReg);
263753f127fSDimitry Andric         if (!MF->getRegInfo().getUniqueVRegDef(Reg))
264753f127fSDimitry Andric           continue;
265753f127fSDimitry Andric         collectDefInstr(Reg, MF, &MAI, MSType, IsFirst);
266753f127fSDimitry Andric         IsFirst = false;
267753f127fSDimitry Andric         if (E->getIsGV())
268753f127fSDimitry Andric           MAI.GlobalVarList.push_back(MF->getRegInfo().getUniqueVRegDef(Reg));
269753f127fSDimitry Andric       }
270753f127fSDimitry Andric 
271753f127fSDimitry Andric       if (UsePreOrder)
272753f127fSDimitry Andric         for (auto *S : E->getDeps())
273753f127fSDimitry Andric           RecHoistUtil(S);
274753f127fSDimitry Andric     };
275753f127fSDimitry Andric     RecHoistUtil(E);
276753f127fSDimitry Andric   }
277753f127fSDimitry Andric }
278753f127fSDimitry Andric 
279753f127fSDimitry Andric // The function initializes global register alias table for types, consts,
280753f127fSDimitry Andric // global vars and func decls and collects these instruction for output
281753f127fSDimitry Andric // at module level. Also it collects explicit OpExtension/OpCapability
282753f127fSDimitry Andric // instructions.
283753f127fSDimitry Andric void SPIRVModuleAnalysis::processDefInstrs(const Module &M) {
284753f127fSDimitry Andric   std::vector<SPIRV::DTSortableEntry *> DepsGraph;
285753f127fSDimitry Andric 
286753f127fSDimitry Andric   GR->buildDepsGraph(DepsGraph, SPVDumpDeps ? MMI : nullptr);
287753f127fSDimitry Andric 
288753f127fSDimitry Andric   collectGlobalEntities(
289753f127fSDimitry Andric       DepsGraph, SPIRV::MB_TypeConstVars,
290fcaf7f86SDimitry Andric       [](const SPIRV::DTSortableEntry *E) { return !E->getIsFunc(); });
291753f127fSDimitry Andric 
292bdd1243dSDimitry Andric   for (auto F = M.begin(), E = M.end(); F != E; ++F) {
293bdd1243dSDimitry Andric     MachineFunction *MF = MMI->getMachineFunction(*F);
294bdd1243dSDimitry Andric     if (!MF)
295bdd1243dSDimitry Andric       continue;
296bdd1243dSDimitry Andric     // Iterate through and collect OpExtension/OpCapability instructions.
297bdd1243dSDimitry Andric     for (MachineBasicBlock &MBB : *MF) {
298bdd1243dSDimitry Andric       for (MachineInstr &MI : MBB) {
299bdd1243dSDimitry Andric         if (MI.getOpcode() == SPIRV::OpExtension) {
300bdd1243dSDimitry Andric           // Here, OpExtension just has a single enum operand, not a string.
301bdd1243dSDimitry Andric           auto Ext = SPIRV::Extension::Extension(MI.getOperand(0).getImm());
302bdd1243dSDimitry Andric           MAI.Reqs.addExtension(Ext);
303bdd1243dSDimitry Andric           MAI.setSkipEmission(&MI);
304bdd1243dSDimitry Andric         } else if (MI.getOpcode() == SPIRV::OpCapability) {
305bdd1243dSDimitry Andric           auto Cap = SPIRV::Capability::Capability(MI.getOperand(0).getImm());
306bdd1243dSDimitry Andric           MAI.Reqs.addCapability(Cap);
307bdd1243dSDimitry Andric           MAI.setSkipEmission(&MI);
308bdd1243dSDimitry Andric         }
309bdd1243dSDimitry Andric       }
310bdd1243dSDimitry Andric     }
311bdd1243dSDimitry Andric   }
312bdd1243dSDimitry Andric 
313753f127fSDimitry Andric   collectGlobalEntities(
314753f127fSDimitry Andric       DepsGraph, SPIRV::MB_ExtFuncDecls,
315753f127fSDimitry Andric       [](const SPIRV::DTSortableEntry *E) { return E->getIsFunc(); }, true);
316753f127fSDimitry Andric }
317753f127fSDimitry Andric 
318bdd1243dSDimitry Andric // Look for IDs declared with Import linkage, and map the corresponding function
31981ad6265SDimitry Andric // to the register defining that variable (which will usually be the result of
32081ad6265SDimitry Andric // an OpFunction). This lets us call externally imported functions using
32181ad6265SDimitry Andric // the correct ID registers.
32281ad6265SDimitry Andric void SPIRVModuleAnalysis::collectFuncNames(MachineInstr &MI,
323bdd1243dSDimitry Andric                                            const Function *F) {
32481ad6265SDimitry Andric   if (MI.getOpcode() == SPIRV::OpDecorate) {
32581ad6265SDimitry Andric     // If it's got Import linkage.
32681ad6265SDimitry Andric     auto Dec = MI.getOperand(1).getImm();
32781ad6265SDimitry Andric     if (Dec == static_cast<unsigned>(SPIRV::Decoration::LinkageAttributes)) {
32881ad6265SDimitry Andric       auto Lnk = MI.getOperand(MI.getNumOperands() - 1).getImm();
32981ad6265SDimitry Andric       if (Lnk == static_cast<unsigned>(SPIRV::LinkageType::Import)) {
33081ad6265SDimitry Andric         // Map imported function name to function ID register.
331bdd1243dSDimitry Andric         const Function *ImportedFunc =
332bdd1243dSDimitry Andric             F->getParent()->getFunction(getStringImm(MI, 2));
33381ad6265SDimitry Andric         Register Target = MI.getOperand(0).getReg();
334bdd1243dSDimitry Andric         MAI.FuncMap[ImportedFunc] = MAI.getRegisterAlias(MI.getMF(), Target);
33581ad6265SDimitry Andric       }
33681ad6265SDimitry Andric     }
33781ad6265SDimitry Andric   } else if (MI.getOpcode() == SPIRV::OpFunction) {
33881ad6265SDimitry Andric     // Record all internal OpFunction declarations.
33981ad6265SDimitry Andric     Register Reg = MI.defs().begin()->getReg();
34081ad6265SDimitry Andric     Register GlobalReg = MAI.getRegisterAlias(MI.getMF(), Reg);
34181ad6265SDimitry Andric     assert(GlobalReg.isValid());
342bdd1243dSDimitry Andric     MAI.FuncMap[F] = GlobalReg;
34381ad6265SDimitry Andric   }
34481ad6265SDimitry Andric }
34581ad6265SDimitry Andric 
346*0fca6ea1SDimitry Andric // References to a function via function pointers generate virtual
347*0fca6ea1SDimitry Andric // registers without a definition. We are able to resolve this
348*0fca6ea1SDimitry Andric // reference using Globar Register info into an OpFunction instruction
349*0fca6ea1SDimitry Andric // and replace dummy operands by the corresponding global register references.
350*0fca6ea1SDimitry Andric void SPIRVModuleAnalysis::collectFuncPtrs() {
351*0fca6ea1SDimitry Andric   for (auto &MI : MAI.MS[SPIRV::MB_TypeConstVars])
352*0fca6ea1SDimitry Andric     if (MI->getOpcode() == SPIRV::OpConstantFunctionPointerINTEL)
353*0fca6ea1SDimitry Andric       collectFuncPtrs(MI);
354*0fca6ea1SDimitry Andric }
355*0fca6ea1SDimitry Andric 
356*0fca6ea1SDimitry Andric void SPIRVModuleAnalysis::collectFuncPtrs(MachineInstr *MI) {
357*0fca6ea1SDimitry Andric   const MachineOperand *FunUse = &MI->getOperand(2);
358*0fca6ea1SDimitry Andric   if (const MachineOperand *FunDef = GR->getFunctionDefinitionByUse(FunUse)) {
359*0fca6ea1SDimitry Andric     const MachineInstr *FunDefMI = FunDef->getParent();
360*0fca6ea1SDimitry Andric     assert(FunDefMI->getOpcode() == SPIRV::OpFunction &&
361*0fca6ea1SDimitry Andric            "Constant function pointer must refer to function definition");
362*0fca6ea1SDimitry Andric     Register FunDefReg = FunDef->getReg();
363*0fca6ea1SDimitry Andric     Register GlobalFunDefReg =
364*0fca6ea1SDimitry Andric         MAI.getRegisterAlias(FunDefMI->getMF(), FunDefReg);
365*0fca6ea1SDimitry Andric     assert(GlobalFunDefReg.isValid() &&
366*0fca6ea1SDimitry Andric            "Function definition must refer to a global register");
367*0fca6ea1SDimitry Andric     Register FunPtrReg = FunUse->getReg();
368*0fca6ea1SDimitry Andric     MAI.setRegisterAlias(MI->getMF(), FunPtrReg, GlobalFunDefReg);
369*0fca6ea1SDimitry Andric   }
370*0fca6ea1SDimitry Andric }
371*0fca6ea1SDimitry Andric 
3727a6dacacSDimitry Andric using InstrSignature = SmallVector<size_t>;
3737a6dacacSDimitry Andric using InstrTraces = std::set<InstrSignature>;
3747a6dacacSDimitry Andric 
3757a6dacacSDimitry Andric // Returns a representation of an instruction as a vector of MachineOperand
3767a6dacacSDimitry Andric // hash values, see llvm::hash_value(const MachineOperand &MO) for details.
3777a6dacacSDimitry Andric // This creates a signature of the instruction with the same content
3787a6dacacSDimitry Andric // that MachineOperand::isIdenticalTo uses for comparison.
3797a6dacacSDimitry Andric static InstrSignature instrToSignature(MachineInstr &MI,
3807a6dacacSDimitry Andric                                        SPIRV::ModuleAnalysisInfo &MAI) {
3817a6dacacSDimitry Andric   InstrSignature Signature;
3827a6dacacSDimitry Andric   for (unsigned i = 0; i < MI.getNumOperands(); ++i) {
3837a6dacacSDimitry Andric     const MachineOperand &MO = MI.getOperand(i);
3847a6dacacSDimitry Andric     size_t h;
3857a6dacacSDimitry Andric     if (MO.isReg()) {
3867a6dacacSDimitry Andric       Register RegAlias = MAI.getRegisterAlias(MI.getMF(), MO.getReg());
3877a6dacacSDimitry Andric       // mimic llvm::hash_value(const MachineOperand &MO)
3887a6dacacSDimitry Andric       h = hash_combine(MO.getType(), (unsigned)RegAlias, MO.getSubReg(),
3897a6dacacSDimitry Andric                        MO.isDef());
3907a6dacacSDimitry Andric     } else {
3917a6dacacSDimitry Andric       h = hash_value(MO);
3927a6dacacSDimitry Andric     }
3937a6dacacSDimitry Andric     Signature.push_back(h);
3947a6dacacSDimitry Andric   }
3957a6dacacSDimitry Andric   return Signature;
3967a6dacacSDimitry Andric }
3977a6dacacSDimitry Andric 
39881ad6265SDimitry Andric // Collect the given instruction in the specified MS. We assume global register
39981ad6265SDimitry Andric // numbering has already occurred by this point. We can directly compare reg
40081ad6265SDimitry Andric // arguments when detecting duplicates.
40181ad6265SDimitry Andric static void collectOtherInstr(MachineInstr &MI, SPIRV::ModuleAnalysisInfo &MAI,
4027a6dacacSDimitry Andric                               SPIRV::ModuleSectionType MSType, InstrTraces &IS,
403fcaf7f86SDimitry Andric                               bool Append = true) {
40481ad6265SDimitry Andric   MAI.setSkipEmission(&MI);
4057a6dacacSDimitry Andric   InstrSignature MISign = instrToSignature(MI, MAI);
4067a6dacacSDimitry Andric   auto FoundMI = IS.insert(MISign);
4077a6dacacSDimitry Andric   if (!FoundMI.second)
4087a6dacacSDimitry Andric     return; // insert failed, so we found a duplicate; don't add it to MAI.MS
40981ad6265SDimitry Andric   // No duplicates, so add it.
410fcaf7f86SDimitry Andric   if (Append)
41181ad6265SDimitry Andric     MAI.MS[MSType].push_back(&MI);
412fcaf7f86SDimitry Andric   else
413fcaf7f86SDimitry Andric     MAI.MS[MSType].insert(MAI.MS[MSType].begin(), &MI);
41481ad6265SDimitry Andric }
41581ad6265SDimitry Andric 
41681ad6265SDimitry Andric // Some global instructions make reference to function-local ID regs, so cannot
41781ad6265SDimitry Andric // be correctly collected until these registers are globally numbered.
41881ad6265SDimitry Andric void SPIRVModuleAnalysis::processOtherInstrs(const Module &M) {
4197a6dacacSDimitry Andric   InstrTraces IS;
42081ad6265SDimitry Andric   for (auto F = M.begin(), E = M.end(); F != E; ++F) {
42181ad6265SDimitry Andric     if ((*F).isDeclaration())
42281ad6265SDimitry Andric       continue;
42381ad6265SDimitry Andric     MachineFunction *MF = MMI->getMachineFunction(*F);
42481ad6265SDimitry Andric     assert(MF);
42581ad6265SDimitry Andric     for (MachineBasicBlock &MBB : *MF)
42681ad6265SDimitry Andric       for (MachineInstr &MI : MBB) {
42781ad6265SDimitry Andric         if (MAI.getSkipEmission(&MI))
42881ad6265SDimitry Andric           continue;
42981ad6265SDimitry Andric         const unsigned OpCode = MI.getOpcode();
43081ad6265SDimitry Andric         if (OpCode == SPIRV::OpName || OpCode == SPIRV::OpMemberName) {
4317a6dacacSDimitry Andric           collectOtherInstr(MI, MAI, SPIRV::MB_DebugNames, IS);
43281ad6265SDimitry Andric         } else if (OpCode == SPIRV::OpEntryPoint) {
4337a6dacacSDimitry Andric           collectOtherInstr(MI, MAI, SPIRV::MB_EntryPoints, IS);
43481ad6265SDimitry Andric         } else if (TII->isDecorationInstr(MI)) {
4357a6dacacSDimitry Andric           collectOtherInstr(MI, MAI, SPIRV::MB_Annotations, IS);
436bdd1243dSDimitry Andric           collectFuncNames(MI, &*F);
437fcaf7f86SDimitry Andric         } else if (TII->isConstantInstr(MI)) {
438fcaf7f86SDimitry Andric           // Now OpSpecConstant*s are not in DT,
439fcaf7f86SDimitry Andric           // but they need to be collected anyway.
4407a6dacacSDimitry Andric           collectOtherInstr(MI, MAI, SPIRV::MB_TypeConstVars, IS);
44181ad6265SDimitry Andric         } else if (OpCode == SPIRV::OpFunction) {
442bdd1243dSDimitry Andric           collectFuncNames(MI, &*F);
443fcaf7f86SDimitry Andric         } else if (OpCode == SPIRV::OpTypeForwardPointer) {
4447a6dacacSDimitry Andric           collectOtherInstr(MI, MAI, SPIRV::MB_TypeConstVars, IS, false);
44581ad6265SDimitry Andric         }
44681ad6265SDimitry Andric       }
44781ad6265SDimitry Andric   }
44881ad6265SDimitry Andric }
44981ad6265SDimitry Andric 
45081ad6265SDimitry Andric // Number registers in all functions globally from 0 onwards and store
451fcaf7f86SDimitry Andric // the result in global register alias table. Some registers are already
452fcaf7f86SDimitry Andric // numbered in collectGlobalEntities.
45381ad6265SDimitry Andric void SPIRVModuleAnalysis::numberRegistersGlobally(const Module &M) {
45481ad6265SDimitry Andric   for (auto F = M.begin(), E = M.end(); F != E; ++F) {
45581ad6265SDimitry Andric     if ((*F).isDeclaration())
45681ad6265SDimitry Andric       continue;
45781ad6265SDimitry Andric     MachineFunction *MF = MMI->getMachineFunction(*F);
45881ad6265SDimitry Andric     assert(MF);
45981ad6265SDimitry Andric     for (MachineBasicBlock &MBB : *MF) {
46081ad6265SDimitry Andric       for (MachineInstr &MI : MBB) {
46181ad6265SDimitry Andric         for (MachineOperand &Op : MI.operands()) {
46281ad6265SDimitry Andric           if (!Op.isReg())
46381ad6265SDimitry Andric             continue;
46481ad6265SDimitry Andric           Register Reg = Op.getReg();
46581ad6265SDimitry Andric           if (MAI.hasRegisterAlias(MF, Reg))
46681ad6265SDimitry Andric             continue;
46781ad6265SDimitry Andric           Register NewReg = Register::index2VirtReg(MAI.getNextID());
46881ad6265SDimitry Andric           MAI.setRegisterAlias(MF, Reg, NewReg);
46981ad6265SDimitry Andric         }
470fcaf7f86SDimitry Andric         if (MI.getOpcode() != SPIRV::OpExtInst)
471fcaf7f86SDimitry Andric           continue;
472fcaf7f86SDimitry Andric         auto Set = MI.getOperand(2).getImm();
473cb14a3feSDimitry Andric         if (!MAI.ExtInstSetMap.contains(Set))
474fcaf7f86SDimitry Andric           MAI.ExtInstSetMap[Set] = Register::index2VirtReg(MAI.getNextID());
47581ad6265SDimitry Andric       }
47681ad6265SDimitry Andric     }
47781ad6265SDimitry Andric   }
47881ad6265SDimitry Andric }
47981ad6265SDimitry Andric 
480bdd1243dSDimitry Andric // RequirementHandler implementations.
481bdd1243dSDimitry Andric void SPIRV::RequirementHandler::getAndAddRequirements(
482bdd1243dSDimitry Andric     SPIRV::OperandCategory::OperandCategory Category, uint32_t i,
483bdd1243dSDimitry Andric     const SPIRVSubtarget &ST) {
484bdd1243dSDimitry Andric   addRequirements(getSymbolicOperandRequirements(Category, i, ST, *this));
485bdd1243dSDimitry Andric }
486bdd1243dSDimitry Andric 
487*0fca6ea1SDimitry Andric void SPIRV::RequirementHandler::recursiveAddCapabilities(
488bdd1243dSDimitry Andric     const CapabilityList &ToPrune) {
489bdd1243dSDimitry Andric   for (const auto &Cap : ToPrune) {
490bdd1243dSDimitry Andric     AllCaps.insert(Cap);
491bdd1243dSDimitry Andric     CapabilityList ImplicitDecls =
492bdd1243dSDimitry Andric         getSymbolicOperandCapabilities(OperandCategory::CapabilityOperand, Cap);
493*0fca6ea1SDimitry Andric     recursiveAddCapabilities(ImplicitDecls);
494bdd1243dSDimitry Andric   }
495bdd1243dSDimitry Andric }
496bdd1243dSDimitry Andric 
497bdd1243dSDimitry Andric void SPIRV::RequirementHandler::addCapabilities(const CapabilityList &ToAdd) {
498bdd1243dSDimitry Andric   for (const auto &Cap : ToAdd) {
499bdd1243dSDimitry Andric     bool IsNewlyInserted = AllCaps.insert(Cap).second;
500bdd1243dSDimitry Andric     if (!IsNewlyInserted) // Don't re-add if it's already been declared.
501bdd1243dSDimitry Andric       continue;
502bdd1243dSDimitry Andric     CapabilityList ImplicitDecls =
503bdd1243dSDimitry Andric         getSymbolicOperandCapabilities(OperandCategory::CapabilityOperand, Cap);
504*0fca6ea1SDimitry Andric     recursiveAddCapabilities(ImplicitDecls);
505bdd1243dSDimitry Andric     MinimalCaps.push_back(Cap);
506bdd1243dSDimitry Andric   }
507bdd1243dSDimitry Andric }
508bdd1243dSDimitry Andric 
509bdd1243dSDimitry Andric void SPIRV::RequirementHandler::addRequirements(
510bdd1243dSDimitry Andric     const SPIRV::Requirements &Req) {
511bdd1243dSDimitry Andric   if (!Req.IsSatisfiable)
512bdd1243dSDimitry Andric     report_fatal_error("Adding SPIR-V requirements this target can't satisfy.");
513bdd1243dSDimitry Andric 
514bdd1243dSDimitry Andric   if (Req.Cap.has_value())
515bdd1243dSDimitry Andric     addCapabilities({Req.Cap.value()});
516bdd1243dSDimitry Andric 
517bdd1243dSDimitry Andric   addExtensions(Req.Exts);
518bdd1243dSDimitry Andric 
519*0fca6ea1SDimitry Andric   if (!Req.MinVer.empty()) {
520*0fca6ea1SDimitry Andric     if (!MaxVersion.empty() && Req.MinVer > MaxVersion) {
521bdd1243dSDimitry Andric       LLVM_DEBUG(dbgs() << "Conflicting version requirements: >= " << Req.MinVer
522bdd1243dSDimitry Andric                         << " and <= " << MaxVersion << "\n");
523bdd1243dSDimitry Andric       report_fatal_error("Adding SPIR-V requirements that can't be satisfied.");
524bdd1243dSDimitry Andric     }
525bdd1243dSDimitry Andric 
526*0fca6ea1SDimitry Andric     if (MinVersion.empty() || Req.MinVer > MinVersion)
527bdd1243dSDimitry Andric       MinVersion = Req.MinVer;
528bdd1243dSDimitry Andric   }
529bdd1243dSDimitry Andric 
530*0fca6ea1SDimitry Andric   if (!Req.MaxVer.empty()) {
531*0fca6ea1SDimitry Andric     if (!MinVersion.empty() && Req.MaxVer < MinVersion) {
532bdd1243dSDimitry Andric       LLVM_DEBUG(dbgs() << "Conflicting version requirements: <= " << Req.MaxVer
533bdd1243dSDimitry Andric                         << " and >= " << MinVersion << "\n");
534bdd1243dSDimitry Andric       report_fatal_error("Adding SPIR-V requirements that can't be satisfied.");
535bdd1243dSDimitry Andric     }
536bdd1243dSDimitry Andric 
537*0fca6ea1SDimitry Andric     if (MaxVersion.empty() || Req.MaxVer < MaxVersion)
538bdd1243dSDimitry Andric       MaxVersion = Req.MaxVer;
539bdd1243dSDimitry Andric   }
540bdd1243dSDimitry Andric }
541bdd1243dSDimitry Andric 
542bdd1243dSDimitry Andric void SPIRV::RequirementHandler::checkSatisfiable(
543bdd1243dSDimitry Andric     const SPIRVSubtarget &ST) const {
544bdd1243dSDimitry Andric   // Report as many errors as possible before aborting the compilation.
545bdd1243dSDimitry Andric   bool IsSatisfiable = true;
546bdd1243dSDimitry Andric   auto TargetVer = ST.getSPIRVVersion();
547bdd1243dSDimitry Andric 
548*0fca6ea1SDimitry Andric   if (!MaxVersion.empty() && !TargetVer.empty() && MaxVersion < TargetVer) {
549bdd1243dSDimitry Andric     LLVM_DEBUG(
550bdd1243dSDimitry Andric         dbgs() << "Target SPIR-V version too high for required features\n"
551bdd1243dSDimitry Andric                << "Required max version: " << MaxVersion << " target version "
552bdd1243dSDimitry Andric                << TargetVer << "\n");
553bdd1243dSDimitry Andric     IsSatisfiable = false;
554bdd1243dSDimitry Andric   }
555bdd1243dSDimitry Andric 
556*0fca6ea1SDimitry Andric   if (!MinVersion.empty() && !TargetVer.empty() && MinVersion > TargetVer) {
557bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "Target SPIR-V version too low for required features\n"
558bdd1243dSDimitry Andric                       << "Required min version: " << MinVersion
559bdd1243dSDimitry Andric                       << " target version " << TargetVer << "\n");
560bdd1243dSDimitry Andric     IsSatisfiable = false;
561bdd1243dSDimitry Andric   }
562bdd1243dSDimitry Andric 
563*0fca6ea1SDimitry Andric   if (!MinVersion.empty() && !MaxVersion.empty() && MinVersion > MaxVersion) {
564bdd1243dSDimitry Andric     LLVM_DEBUG(
565bdd1243dSDimitry Andric         dbgs()
566bdd1243dSDimitry Andric         << "Version is too low for some features and too high for others.\n"
567bdd1243dSDimitry Andric         << "Required SPIR-V min version: " << MinVersion
568bdd1243dSDimitry Andric         << " required SPIR-V max version " << MaxVersion << "\n");
569bdd1243dSDimitry Andric     IsSatisfiable = false;
570bdd1243dSDimitry Andric   }
571bdd1243dSDimitry Andric 
572bdd1243dSDimitry Andric   for (auto Cap : MinimalCaps) {
573bdd1243dSDimitry Andric     if (AvailableCaps.contains(Cap))
574bdd1243dSDimitry Andric       continue;
575bdd1243dSDimitry Andric     LLVM_DEBUG(dbgs() << "Capability not supported: "
576bdd1243dSDimitry Andric                       << getSymbolicOperandMnemonic(
577bdd1243dSDimitry Andric                              OperandCategory::CapabilityOperand, Cap)
578bdd1243dSDimitry Andric                       << "\n");
579bdd1243dSDimitry Andric     IsSatisfiable = false;
580bdd1243dSDimitry Andric   }
581bdd1243dSDimitry Andric 
582bdd1243dSDimitry Andric   for (auto Ext : AllExtensions) {
583bdd1243dSDimitry Andric     if (ST.canUseExtension(Ext))
584bdd1243dSDimitry Andric       continue;
5855f757f3fSDimitry Andric     LLVM_DEBUG(dbgs() << "Extension not supported: "
586bdd1243dSDimitry Andric                       << getSymbolicOperandMnemonic(
587bdd1243dSDimitry Andric                              OperandCategory::ExtensionOperand, Ext)
588bdd1243dSDimitry Andric                       << "\n");
589bdd1243dSDimitry Andric     IsSatisfiable = false;
590bdd1243dSDimitry Andric   }
591bdd1243dSDimitry Andric 
592bdd1243dSDimitry Andric   if (!IsSatisfiable)
593bdd1243dSDimitry Andric     report_fatal_error("Unable to meet SPIR-V requirements for this target.");
594bdd1243dSDimitry Andric }
595bdd1243dSDimitry Andric 
596bdd1243dSDimitry Andric // Add the given capabilities and all their implicitly defined capabilities too.
597bdd1243dSDimitry Andric void SPIRV::RequirementHandler::addAvailableCaps(const CapabilityList &ToAdd) {
598bdd1243dSDimitry Andric   for (const auto Cap : ToAdd)
599bdd1243dSDimitry Andric     if (AvailableCaps.insert(Cap).second)
600bdd1243dSDimitry Andric       addAvailableCaps(getSymbolicOperandCapabilities(
601bdd1243dSDimitry Andric           SPIRV::OperandCategory::CapabilityOperand, Cap));
602bdd1243dSDimitry Andric }
603bdd1243dSDimitry Andric 
6045f757f3fSDimitry Andric void SPIRV::RequirementHandler::removeCapabilityIf(
6055f757f3fSDimitry Andric     const Capability::Capability ToRemove,
6065f757f3fSDimitry Andric     const Capability::Capability IfPresent) {
6075f757f3fSDimitry Andric   if (AllCaps.contains(IfPresent))
6085f757f3fSDimitry Andric     AllCaps.erase(ToRemove);
6095f757f3fSDimitry Andric }
6105f757f3fSDimitry Andric 
611bdd1243dSDimitry Andric namespace llvm {
612bdd1243dSDimitry Andric namespace SPIRV {
613bdd1243dSDimitry Andric void RequirementHandler::initAvailableCapabilities(const SPIRVSubtarget &ST) {
6145f757f3fSDimitry Andric   if (ST.isOpenCLEnv()) {
6155f757f3fSDimitry Andric     initAvailableCapabilitiesForOpenCL(ST);
616bdd1243dSDimitry Andric     return;
6175f757f3fSDimitry Andric   }
6185f757f3fSDimitry Andric 
6195f757f3fSDimitry Andric   if (ST.isVulkanEnv()) {
6205f757f3fSDimitry Andric     initAvailableCapabilitiesForVulkan(ST);
6215f757f3fSDimitry Andric     return;
6225f757f3fSDimitry Andric   }
6235f757f3fSDimitry Andric 
6245f757f3fSDimitry Andric   report_fatal_error("Unimplemented environment for SPIR-V generation.");
6255f757f3fSDimitry Andric }
6265f757f3fSDimitry Andric 
6275f757f3fSDimitry Andric void RequirementHandler::initAvailableCapabilitiesForOpenCL(
6285f757f3fSDimitry Andric     const SPIRVSubtarget &ST) {
629bdd1243dSDimitry Andric   // Add the min requirements for different OpenCL and SPIR-V versions.
630bdd1243dSDimitry Andric   addAvailableCaps({Capability::Addresses, Capability::Float16Buffer,
631bdd1243dSDimitry Andric                     Capability::Int16, Capability::Int8, Capability::Kernel,
632bdd1243dSDimitry Andric                     Capability::Linkage, Capability::Vector16,
633bdd1243dSDimitry Andric                     Capability::Groups, Capability::GenericPointer,
634bdd1243dSDimitry Andric                     Capability::Shader});
635bdd1243dSDimitry Andric   if (ST.hasOpenCLFullProfile())
636bdd1243dSDimitry Andric     addAvailableCaps({Capability::Int64, Capability::Int64Atomics});
637bdd1243dSDimitry Andric   if (ST.hasOpenCLImageSupport()) {
638bdd1243dSDimitry Andric     addAvailableCaps({Capability::ImageBasic, Capability::LiteralSampler,
639bdd1243dSDimitry Andric                       Capability::Image1D, Capability::SampledBuffer,
640bdd1243dSDimitry Andric                       Capability::ImageBuffer});
641*0fca6ea1SDimitry Andric     if (ST.isAtLeastOpenCLVer(VersionTuple(2, 0)))
642bdd1243dSDimitry Andric       addAvailableCaps({Capability::ImageReadWrite});
643bdd1243dSDimitry Andric   }
644*0fca6ea1SDimitry Andric   if (ST.isAtLeastSPIRVVer(VersionTuple(1, 1)) &&
645*0fca6ea1SDimitry Andric       ST.isAtLeastOpenCLVer(VersionTuple(2, 2)))
646bdd1243dSDimitry Andric     addAvailableCaps({Capability::SubgroupDispatch, Capability::PipeStorage});
647*0fca6ea1SDimitry Andric   if (ST.isAtLeastSPIRVVer(VersionTuple(1, 3)))
648bdd1243dSDimitry Andric     addAvailableCaps({Capability::GroupNonUniform,
649bdd1243dSDimitry Andric                       Capability::GroupNonUniformVote,
650bdd1243dSDimitry Andric                       Capability::GroupNonUniformArithmetic,
651bdd1243dSDimitry Andric                       Capability::GroupNonUniformBallot,
652bdd1243dSDimitry Andric                       Capability::GroupNonUniformClustered,
653bdd1243dSDimitry Andric                       Capability::GroupNonUniformShuffle,
654bdd1243dSDimitry Andric                       Capability::GroupNonUniformShuffleRelative});
655*0fca6ea1SDimitry Andric   if (ST.isAtLeastSPIRVVer(VersionTuple(1, 4)))
656bdd1243dSDimitry Andric     addAvailableCaps({Capability::DenormPreserve, Capability::DenormFlushToZero,
657bdd1243dSDimitry Andric                       Capability::SignedZeroInfNanPreserve,
658bdd1243dSDimitry Andric                       Capability::RoundingModeRTE,
659bdd1243dSDimitry Andric                       Capability::RoundingModeRTZ});
660bdd1243dSDimitry Andric   // TODO: verify if this needs some checks.
661bdd1243dSDimitry Andric   addAvailableCaps({Capability::Float16, Capability::Float64});
662bdd1243dSDimitry Andric 
6635f757f3fSDimitry Andric   // Add capabilities enabled by extensions.
6645f757f3fSDimitry Andric   for (auto Extension : ST.getAllAvailableExtensions()) {
6655f757f3fSDimitry Andric     CapabilityList EnabledCapabilities =
6665f757f3fSDimitry Andric         getCapabilitiesEnabledByExtension(Extension);
6675f757f3fSDimitry Andric     addAvailableCaps(EnabledCapabilities);
6685f757f3fSDimitry Andric   }
6695f757f3fSDimitry Andric 
670bdd1243dSDimitry Andric   // TODO: add OpenCL extensions.
671bdd1243dSDimitry Andric }
6725f757f3fSDimitry Andric 
6735f757f3fSDimitry Andric void RequirementHandler::initAvailableCapabilitiesForVulkan(
6745f757f3fSDimitry Andric     const SPIRVSubtarget &ST) {
6755f757f3fSDimitry Andric   addAvailableCaps({Capability::Shader, Capability::Linkage});
6765f757f3fSDimitry Andric 
6777a6dacacSDimitry Andric   // Provided by all supported Vulkan versions.
6787a6dacacSDimitry Andric   addAvailableCaps({Capability::Int16, Capability::Int64, Capability::Float16,
679*0fca6ea1SDimitry Andric                     Capability::Float64, Capability::GroupNonUniform});
6805f757f3fSDimitry Andric }
6815f757f3fSDimitry Andric 
682bdd1243dSDimitry Andric } // namespace SPIRV
683bdd1243dSDimitry Andric } // namespace llvm
684bdd1243dSDimitry Andric 
685bdd1243dSDimitry Andric // Add the required capabilities from a decoration instruction (including
686bdd1243dSDimitry Andric // BuiltIns).
687bdd1243dSDimitry Andric static void addOpDecorateReqs(const MachineInstr &MI, unsigned DecIndex,
688bdd1243dSDimitry Andric                               SPIRV::RequirementHandler &Reqs,
689bdd1243dSDimitry Andric                               const SPIRVSubtarget &ST) {
690bdd1243dSDimitry Andric   int64_t DecOp = MI.getOperand(DecIndex).getImm();
691bdd1243dSDimitry Andric   auto Dec = static_cast<SPIRV::Decoration::Decoration>(DecOp);
692bdd1243dSDimitry Andric   Reqs.addRequirements(getSymbolicOperandRequirements(
693bdd1243dSDimitry Andric       SPIRV::OperandCategory::DecorationOperand, Dec, ST, Reqs));
694bdd1243dSDimitry Andric 
695bdd1243dSDimitry Andric   if (Dec == SPIRV::Decoration::BuiltIn) {
696bdd1243dSDimitry Andric     int64_t BuiltInOp = MI.getOperand(DecIndex + 1).getImm();
697bdd1243dSDimitry Andric     auto BuiltIn = static_cast<SPIRV::BuiltIn::BuiltIn>(BuiltInOp);
698bdd1243dSDimitry Andric     Reqs.addRequirements(getSymbolicOperandRequirements(
699bdd1243dSDimitry Andric         SPIRV::OperandCategory::BuiltInOperand, BuiltIn, ST, Reqs));
700*0fca6ea1SDimitry Andric   } else if (Dec == SPIRV::Decoration::LinkageAttributes) {
701*0fca6ea1SDimitry Andric     int64_t LinkageOp = MI.getOperand(MI.getNumOperands() - 1).getImm();
702*0fca6ea1SDimitry Andric     SPIRV::LinkageType::LinkageType LnkType =
703*0fca6ea1SDimitry Andric         static_cast<SPIRV::LinkageType::LinkageType>(LinkageOp);
704*0fca6ea1SDimitry Andric     if (LnkType == SPIRV::LinkageType::LinkOnceODR)
705*0fca6ea1SDimitry Andric       Reqs.addExtension(SPIRV::Extension::SPV_KHR_linkonce_odr);
706*0fca6ea1SDimitry Andric   } else if (Dec == SPIRV::Decoration::CacheControlLoadINTEL ||
707*0fca6ea1SDimitry Andric              Dec == SPIRV::Decoration::CacheControlStoreINTEL) {
708*0fca6ea1SDimitry Andric     Reqs.addExtension(SPIRV::Extension::SPV_INTEL_cache_controls);
709*0fca6ea1SDimitry Andric   } else if (Dec == SPIRV::Decoration::HostAccessINTEL) {
710*0fca6ea1SDimitry Andric     Reqs.addExtension(SPIRV::Extension::SPV_INTEL_global_variable_host_access);
711*0fca6ea1SDimitry Andric   } else if (Dec == SPIRV::Decoration::InitModeINTEL ||
712*0fca6ea1SDimitry Andric              Dec == SPIRV::Decoration::ImplementInRegisterMapINTEL) {
713*0fca6ea1SDimitry Andric     Reqs.addExtension(
714*0fca6ea1SDimitry Andric         SPIRV::Extension::SPV_INTEL_global_variable_fpga_decorations);
715bdd1243dSDimitry Andric   }
716bdd1243dSDimitry Andric }
717bdd1243dSDimitry Andric 
718bdd1243dSDimitry Andric // Add requirements for image handling.
719bdd1243dSDimitry Andric static void addOpTypeImageReqs(const MachineInstr &MI,
720bdd1243dSDimitry Andric                                SPIRV::RequirementHandler &Reqs,
721bdd1243dSDimitry Andric                                const SPIRVSubtarget &ST) {
722bdd1243dSDimitry Andric   assert(MI.getNumOperands() >= 8 && "Insufficient operands for OpTypeImage");
723bdd1243dSDimitry Andric   // The operand indices used here are based on the OpTypeImage layout, which
724bdd1243dSDimitry Andric   // the MachineInstr follows as well.
725bdd1243dSDimitry Andric   int64_t ImgFormatOp = MI.getOperand(7).getImm();
726bdd1243dSDimitry Andric   auto ImgFormat = static_cast<SPIRV::ImageFormat::ImageFormat>(ImgFormatOp);
727bdd1243dSDimitry Andric   Reqs.getAndAddRequirements(SPIRV::OperandCategory::ImageFormatOperand,
728bdd1243dSDimitry Andric                              ImgFormat, ST);
729bdd1243dSDimitry Andric 
730bdd1243dSDimitry Andric   bool IsArrayed = MI.getOperand(4).getImm() == 1;
731bdd1243dSDimitry Andric   bool IsMultisampled = MI.getOperand(5).getImm() == 1;
732bdd1243dSDimitry Andric   bool NoSampler = MI.getOperand(6).getImm() == 2;
733bdd1243dSDimitry Andric   // Add dimension requirements.
734bdd1243dSDimitry Andric   assert(MI.getOperand(2).isImm());
735bdd1243dSDimitry Andric   switch (MI.getOperand(2).getImm()) {
736bdd1243dSDimitry Andric   case SPIRV::Dim::DIM_1D:
737bdd1243dSDimitry Andric     Reqs.addRequirements(NoSampler ? SPIRV::Capability::Image1D
738bdd1243dSDimitry Andric                                    : SPIRV::Capability::Sampled1D);
739bdd1243dSDimitry Andric     break;
740bdd1243dSDimitry Andric   case SPIRV::Dim::DIM_2D:
741bdd1243dSDimitry Andric     if (IsMultisampled && NoSampler)
742bdd1243dSDimitry Andric       Reqs.addRequirements(SPIRV::Capability::ImageMSArray);
743bdd1243dSDimitry Andric     break;
744bdd1243dSDimitry Andric   case SPIRV::Dim::DIM_Cube:
745bdd1243dSDimitry Andric     Reqs.addRequirements(SPIRV::Capability::Shader);
746bdd1243dSDimitry Andric     if (IsArrayed)
747bdd1243dSDimitry Andric       Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageCubeArray
748bdd1243dSDimitry Andric                                      : SPIRV::Capability::SampledCubeArray);
749bdd1243dSDimitry Andric     break;
750bdd1243dSDimitry Andric   case SPIRV::Dim::DIM_Rect:
751bdd1243dSDimitry Andric     Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageRect
752bdd1243dSDimitry Andric                                    : SPIRV::Capability::SampledRect);
753bdd1243dSDimitry Andric     break;
754bdd1243dSDimitry Andric   case SPIRV::Dim::DIM_Buffer:
755bdd1243dSDimitry Andric     Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageBuffer
756bdd1243dSDimitry Andric                                    : SPIRV::Capability::SampledBuffer);
757bdd1243dSDimitry Andric     break;
758bdd1243dSDimitry Andric   case SPIRV::Dim::DIM_SubpassData:
759bdd1243dSDimitry Andric     Reqs.addRequirements(SPIRV::Capability::InputAttachment);
760bdd1243dSDimitry Andric     break;
761bdd1243dSDimitry Andric   }
762bdd1243dSDimitry Andric 
763bdd1243dSDimitry Andric   // Has optional access qualifier.
764bdd1243dSDimitry Andric   // TODO: check if it's OpenCL's kernel.
765bdd1243dSDimitry Andric   if (MI.getNumOperands() > 8 &&
766bdd1243dSDimitry Andric       MI.getOperand(8).getImm() == SPIRV::AccessQualifier::ReadWrite)
767bdd1243dSDimitry Andric     Reqs.addRequirements(SPIRV::Capability::ImageReadWrite);
768bdd1243dSDimitry Andric   else
769bdd1243dSDimitry Andric     Reqs.addRequirements(SPIRV::Capability::ImageBasic);
770bdd1243dSDimitry Andric }
771bdd1243dSDimitry Andric 
772*0fca6ea1SDimitry Andric // Add requirements for handling atomic float instructions
773*0fca6ea1SDimitry Andric #define ATOM_FLT_REQ_EXT_MSG(ExtName)                                          \
774*0fca6ea1SDimitry Andric   "The atomic float instruction requires the following SPIR-V "                \
775*0fca6ea1SDimitry Andric   "extension: SPV_EXT_shader_atomic_float" ExtName
776*0fca6ea1SDimitry Andric static void AddAtomicFloatRequirements(const MachineInstr &MI,
777*0fca6ea1SDimitry Andric                                        SPIRV::RequirementHandler &Reqs,
778*0fca6ea1SDimitry Andric                                        const SPIRVSubtarget &ST) {
779*0fca6ea1SDimitry Andric   assert(MI.getOperand(1).isReg() &&
780*0fca6ea1SDimitry Andric          "Expect register operand in atomic float instruction");
781*0fca6ea1SDimitry Andric   Register TypeReg = MI.getOperand(1).getReg();
782*0fca6ea1SDimitry Andric   SPIRVType *TypeDef = MI.getMF()->getRegInfo().getVRegDef(TypeReg);
783*0fca6ea1SDimitry Andric   if (TypeDef->getOpcode() != SPIRV::OpTypeFloat)
784*0fca6ea1SDimitry Andric     report_fatal_error("Result type of an atomic float instruction must be a "
785*0fca6ea1SDimitry Andric                        "floating-point type scalar");
786*0fca6ea1SDimitry Andric 
787*0fca6ea1SDimitry Andric   unsigned BitWidth = TypeDef->getOperand(1).getImm();
788*0fca6ea1SDimitry Andric   unsigned Op = MI.getOpcode();
789*0fca6ea1SDimitry Andric   if (Op == SPIRV::OpAtomicFAddEXT) {
790*0fca6ea1SDimitry Andric     if (!ST.canUseExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_add))
791*0fca6ea1SDimitry Andric       report_fatal_error(ATOM_FLT_REQ_EXT_MSG("_add"), false);
792*0fca6ea1SDimitry Andric     Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_add);
793*0fca6ea1SDimitry Andric     switch (BitWidth) {
794*0fca6ea1SDimitry Andric     case 16:
795*0fca6ea1SDimitry Andric       if (!ST.canUseExtension(
796*0fca6ea1SDimitry Andric               SPIRV::Extension::SPV_EXT_shader_atomic_float16_add))
797*0fca6ea1SDimitry Andric         report_fatal_error(ATOM_FLT_REQ_EXT_MSG("16_add"), false);
798*0fca6ea1SDimitry Andric       Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float16_add);
799*0fca6ea1SDimitry Andric       Reqs.addCapability(SPIRV::Capability::AtomicFloat16AddEXT);
800*0fca6ea1SDimitry Andric       break;
801*0fca6ea1SDimitry Andric     case 32:
802*0fca6ea1SDimitry Andric       Reqs.addCapability(SPIRV::Capability::AtomicFloat32AddEXT);
803*0fca6ea1SDimitry Andric       break;
804*0fca6ea1SDimitry Andric     case 64:
805*0fca6ea1SDimitry Andric       Reqs.addCapability(SPIRV::Capability::AtomicFloat64AddEXT);
806*0fca6ea1SDimitry Andric       break;
807*0fca6ea1SDimitry Andric     default:
808*0fca6ea1SDimitry Andric       report_fatal_error(
809*0fca6ea1SDimitry Andric           "Unexpected floating-point type width in atomic float instruction");
810*0fca6ea1SDimitry Andric     }
811*0fca6ea1SDimitry Andric   } else {
812*0fca6ea1SDimitry Andric     if (!ST.canUseExtension(
813*0fca6ea1SDimitry Andric             SPIRV::Extension::SPV_EXT_shader_atomic_float_min_max))
814*0fca6ea1SDimitry Andric       report_fatal_error(ATOM_FLT_REQ_EXT_MSG("_min_max"), false);
815*0fca6ea1SDimitry Andric     Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_min_max);
816*0fca6ea1SDimitry Andric     switch (BitWidth) {
817*0fca6ea1SDimitry Andric     case 16:
818*0fca6ea1SDimitry Andric       Reqs.addCapability(SPIRV::Capability::AtomicFloat16MinMaxEXT);
819*0fca6ea1SDimitry Andric       break;
820*0fca6ea1SDimitry Andric     case 32:
821*0fca6ea1SDimitry Andric       Reqs.addCapability(SPIRV::Capability::AtomicFloat32MinMaxEXT);
822*0fca6ea1SDimitry Andric       break;
823*0fca6ea1SDimitry Andric     case 64:
824*0fca6ea1SDimitry Andric       Reqs.addCapability(SPIRV::Capability::AtomicFloat64MinMaxEXT);
825*0fca6ea1SDimitry Andric       break;
826*0fca6ea1SDimitry Andric     default:
827*0fca6ea1SDimitry Andric       report_fatal_error(
828*0fca6ea1SDimitry Andric           "Unexpected floating-point type width in atomic float instruction");
829*0fca6ea1SDimitry Andric     }
830*0fca6ea1SDimitry Andric   }
831*0fca6ea1SDimitry Andric }
832*0fca6ea1SDimitry Andric 
833bdd1243dSDimitry Andric void addInstrRequirements(const MachineInstr &MI,
834bdd1243dSDimitry Andric                           SPIRV::RequirementHandler &Reqs,
835bdd1243dSDimitry Andric                           const SPIRVSubtarget &ST) {
836bdd1243dSDimitry Andric   switch (MI.getOpcode()) {
837bdd1243dSDimitry Andric   case SPIRV::OpMemoryModel: {
838bdd1243dSDimitry Andric     int64_t Addr = MI.getOperand(0).getImm();
839bdd1243dSDimitry Andric     Reqs.getAndAddRequirements(SPIRV::OperandCategory::AddressingModelOperand,
840bdd1243dSDimitry Andric                                Addr, ST);
841bdd1243dSDimitry Andric     int64_t Mem = MI.getOperand(1).getImm();
842bdd1243dSDimitry Andric     Reqs.getAndAddRequirements(SPIRV::OperandCategory::MemoryModelOperand, Mem,
843bdd1243dSDimitry Andric                                ST);
844bdd1243dSDimitry Andric     break;
845bdd1243dSDimitry Andric   }
846bdd1243dSDimitry Andric   case SPIRV::OpEntryPoint: {
847bdd1243dSDimitry Andric     int64_t Exe = MI.getOperand(0).getImm();
848bdd1243dSDimitry Andric     Reqs.getAndAddRequirements(SPIRV::OperandCategory::ExecutionModelOperand,
849bdd1243dSDimitry Andric                                Exe, ST);
850bdd1243dSDimitry Andric     break;
851bdd1243dSDimitry Andric   }
852bdd1243dSDimitry Andric   case SPIRV::OpExecutionMode:
853bdd1243dSDimitry Andric   case SPIRV::OpExecutionModeId: {
854bdd1243dSDimitry Andric     int64_t Exe = MI.getOperand(1).getImm();
855bdd1243dSDimitry Andric     Reqs.getAndAddRequirements(SPIRV::OperandCategory::ExecutionModeOperand,
856bdd1243dSDimitry Andric                                Exe, ST);
857bdd1243dSDimitry Andric     break;
858bdd1243dSDimitry Andric   }
859bdd1243dSDimitry Andric   case SPIRV::OpTypeMatrix:
860bdd1243dSDimitry Andric     Reqs.addCapability(SPIRV::Capability::Matrix);
861bdd1243dSDimitry Andric     break;
862bdd1243dSDimitry Andric   case SPIRV::OpTypeInt: {
863bdd1243dSDimitry Andric     unsigned BitWidth = MI.getOperand(1).getImm();
864bdd1243dSDimitry Andric     if (BitWidth == 64)
865bdd1243dSDimitry Andric       Reqs.addCapability(SPIRV::Capability::Int64);
866bdd1243dSDimitry Andric     else if (BitWidth == 16)
867bdd1243dSDimitry Andric       Reqs.addCapability(SPIRV::Capability::Int16);
868bdd1243dSDimitry Andric     else if (BitWidth == 8)
869bdd1243dSDimitry Andric       Reqs.addCapability(SPIRV::Capability::Int8);
870bdd1243dSDimitry Andric     break;
871bdd1243dSDimitry Andric   }
872bdd1243dSDimitry Andric   case SPIRV::OpTypeFloat: {
873bdd1243dSDimitry Andric     unsigned BitWidth = MI.getOperand(1).getImm();
874bdd1243dSDimitry Andric     if (BitWidth == 64)
875bdd1243dSDimitry Andric       Reqs.addCapability(SPIRV::Capability::Float64);
876bdd1243dSDimitry Andric     else if (BitWidth == 16)
877bdd1243dSDimitry Andric       Reqs.addCapability(SPIRV::Capability::Float16);
878bdd1243dSDimitry Andric     break;
879bdd1243dSDimitry Andric   }
880bdd1243dSDimitry Andric   case SPIRV::OpTypeVector: {
881bdd1243dSDimitry Andric     unsigned NumComponents = MI.getOperand(2).getImm();
882bdd1243dSDimitry Andric     if (NumComponents == 8 || NumComponents == 16)
883bdd1243dSDimitry Andric       Reqs.addCapability(SPIRV::Capability::Vector16);
884bdd1243dSDimitry Andric     break;
885bdd1243dSDimitry Andric   }
886bdd1243dSDimitry Andric   case SPIRV::OpTypePointer: {
887bdd1243dSDimitry Andric     auto SC = MI.getOperand(1).getImm();
888bdd1243dSDimitry Andric     Reqs.getAndAddRequirements(SPIRV::OperandCategory::StorageClassOperand, SC,
889bdd1243dSDimitry Andric                                ST);
8907a6dacacSDimitry Andric     // If it's a type of pointer to float16 targeting OpenCL, add Float16Buffer
8917a6dacacSDimitry Andric     // capability.
8927a6dacacSDimitry Andric     if (!ST.isOpenCLEnv())
8937a6dacacSDimitry Andric       break;
894bdd1243dSDimitry Andric     assert(MI.getOperand(2).isReg());
895bdd1243dSDimitry Andric     const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
896bdd1243dSDimitry Andric     SPIRVType *TypeDef = MRI.getVRegDef(MI.getOperand(2).getReg());
897bdd1243dSDimitry Andric     if (TypeDef->getOpcode() == SPIRV::OpTypeFloat &&
898bdd1243dSDimitry Andric         TypeDef->getOperand(1).getImm() == 16)
899bdd1243dSDimitry Andric       Reqs.addCapability(SPIRV::Capability::Float16Buffer);
900bdd1243dSDimitry Andric     break;
901bdd1243dSDimitry Andric   }
902bdd1243dSDimitry Andric   case SPIRV::OpBitReverse:
9035f757f3fSDimitry Andric   case SPIRV::OpBitFieldInsert:
9045f757f3fSDimitry Andric   case SPIRV::OpBitFieldSExtract:
9055f757f3fSDimitry Andric   case SPIRV::OpBitFieldUExtract:
9065f757f3fSDimitry Andric     if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions)) {
9075f757f3fSDimitry Andric       Reqs.addCapability(SPIRV::Capability::Shader);
9085f757f3fSDimitry Andric       break;
9095f757f3fSDimitry Andric     }
9105f757f3fSDimitry Andric     Reqs.addExtension(SPIRV::Extension::SPV_KHR_bit_instructions);
9115f757f3fSDimitry Andric     Reqs.addCapability(SPIRV::Capability::BitInstructions);
9125f757f3fSDimitry Andric     break;
913bdd1243dSDimitry Andric   case SPIRV::OpTypeRuntimeArray:
914bdd1243dSDimitry Andric     Reqs.addCapability(SPIRV::Capability::Shader);
915bdd1243dSDimitry Andric     break;
916bdd1243dSDimitry Andric   case SPIRV::OpTypeOpaque:
917bdd1243dSDimitry Andric   case SPIRV::OpTypeEvent:
918bdd1243dSDimitry Andric     Reqs.addCapability(SPIRV::Capability::Kernel);
919bdd1243dSDimitry Andric     break;
920bdd1243dSDimitry Andric   case SPIRV::OpTypePipe:
921bdd1243dSDimitry Andric   case SPIRV::OpTypeReserveId:
922bdd1243dSDimitry Andric     Reqs.addCapability(SPIRV::Capability::Pipes);
923bdd1243dSDimitry Andric     break;
924bdd1243dSDimitry Andric   case SPIRV::OpTypeDeviceEvent:
925bdd1243dSDimitry Andric   case SPIRV::OpTypeQueue:
926bdd1243dSDimitry Andric   case SPIRV::OpBuildNDRange:
927bdd1243dSDimitry Andric     Reqs.addCapability(SPIRV::Capability::DeviceEnqueue);
928bdd1243dSDimitry Andric     break;
929bdd1243dSDimitry Andric   case SPIRV::OpDecorate:
930bdd1243dSDimitry Andric   case SPIRV::OpDecorateId:
931bdd1243dSDimitry Andric   case SPIRV::OpDecorateString:
932bdd1243dSDimitry Andric     addOpDecorateReqs(MI, 1, Reqs, ST);
933bdd1243dSDimitry Andric     break;
934bdd1243dSDimitry Andric   case SPIRV::OpMemberDecorate:
935bdd1243dSDimitry Andric   case SPIRV::OpMemberDecorateString:
936bdd1243dSDimitry Andric     addOpDecorateReqs(MI, 2, Reqs, ST);
937bdd1243dSDimitry Andric     break;
938bdd1243dSDimitry Andric   case SPIRV::OpInBoundsPtrAccessChain:
939bdd1243dSDimitry Andric     Reqs.addCapability(SPIRV::Capability::Addresses);
940bdd1243dSDimitry Andric     break;
941bdd1243dSDimitry Andric   case SPIRV::OpConstantSampler:
942bdd1243dSDimitry Andric     Reqs.addCapability(SPIRV::Capability::LiteralSampler);
943bdd1243dSDimitry Andric     break;
944bdd1243dSDimitry Andric   case SPIRV::OpTypeImage:
945bdd1243dSDimitry Andric     addOpTypeImageReqs(MI, Reqs, ST);
946bdd1243dSDimitry Andric     break;
947bdd1243dSDimitry Andric   case SPIRV::OpTypeSampler:
948bdd1243dSDimitry Andric     Reqs.addCapability(SPIRV::Capability::ImageBasic);
949bdd1243dSDimitry Andric     break;
950bdd1243dSDimitry Andric   case SPIRV::OpTypeForwardPointer:
951bdd1243dSDimitry Andric     // TODO: check if it's OpenCL's kernel.
952bdd1243dSDimitry Andric     Reqs.addCapability(SPIRV::Capability::Addresses);
953bdd1243dSDimitry Andric     break;
954bdd1243dSDimitry Andric   case SPIRV::OpAtomicFlagTestAndSet:
955bdd1243dSDimitry Andric   case SPIRV::OpAtomicLoad:
956bdd1243dSDimitry Andric   case SPIRV::OpAtomicStore:
957bdd1243dSDimitry Andric   case SPIRV::OpAtomicExchange:
958bdd1243dSDimitry Andric   case SPIRV::OpAtomicCompareExchange:
959bdd1243dSDimitry Andric   case SPIRV::OpAtomicIIncrement:
960bdd1243dSDimitry Andric   case SPIRV::OpAtomicIDecrement:
961bdd1243dSDimitry Andric   case SPIRV::OpAtomicIAdd:
962bdd1243dSDimitry Andric   case SPIRV::OpAtomicISub:
963bdd1243dSDimitry Andric   case SPIRV::OpAtomicUMin:
964bdd1243dSDimitry Andric   case SPIRV::OpAtomicUMax:
965bdd1243dSDimitry Andric   case SPIRV::OpAtomicSMin:
966bdd1243dSDimitry Andric   case SPIRV::OpAtomicSMax:
967bdd1243dSDimitry Andric   case SPIRV::OpAtomicAnd:
968bdd1243dSDimitry Andric   case SPIRV::OpAtomicOr:
969bdd1243dSDimitry Andric   case SPIRV::OpAtomicXor: {
970bdd1243dSDimitry Andric     const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
971bdd1243dSDimitry Andric     const MachineInstr *InstrPtr = &MI;
972bdd1243dSDimitry Andric     if (MI.getOpcode() == SPIRV::OpAtomicStore) {
973bdd1243dSDimitry Andric       assert(MI.getOperand(3).isReg());
974bdd1243dSDimitry Andric       InstrPtr = MRI.getVRegDef(MI.getOperand(3).getReg());
975bdd1243dSDimitry Andric       assert(InstrPtr && "Unexpected type instruction for OpAtomicStore");
976bdd1243dSDimitry Andric     }
977bdd1243dSDimitry Andric     assert(InstrPtr->getOperand(1).isReg() && "Unexpected operand in atomic");
978bdd1243dSDimitry Andric     Register TypeReg = InstrPtr->getOperand(1).getReg();
979bdd1243dSDimitry Andric     SPIRVType *TypeDef = MRI.getVRegDef(TypeReg);
980bdd1243dSDimitry Andric     if (TypeDef->getOpcode() == SPIRV::OpTypeInt) {
981bdd1243dSDimitry Andric       unsigned BitWidth = TypeDef->getOperand(1).getImm();
982bdd1243dSDimitry Andric       if (BitWidth == 64)
983bdd1243dSDimitry Andric         Reqs.addCapability(SPIRV::Capability::Int64Atomics);
984bdd1243dSDimitry Andric     }
985bdd1243dSDimitry Andric     break;
986bdd1243dSDimitry Andric   }
987bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformIAdd:
988bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformFAdd:
989bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformIMul:
990bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformFMul:
991bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformSMin:
992bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformUMin:
993bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformFMin:
994bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformSMax:
995bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformUMax:
996bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformFMax:
997bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformBitwiseAnd:
998bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformBitwiseOr:
999bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformBitwiseXor:
1000bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformLogicalAnd:
1001bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformLogicalOr:
1002bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformLogicalXor: {
1003bdd1243dSDimitry Andric     assert(MI.getOperand(3).isImm());
1004bdd1243dSDimitry Andric     int64_t GroupOp = MI.getOperand(3).getImm();
1005bdd1243dSDimitry Andric     switch (GroupOp) {
1006bdd1243dSDimitry Andric     case SPIRV::GroupOperation::Reduce:
1007bdd1243dSDimitry Andric     case SPIRV::GroupOperation::InclusiveScan:
1008bdd1243dSDimitry Andric     case SPIRV::GroupOperation::ExclusiveScan:
1009bdd1243dSDimitry Andric       Reqs.addCapability(SPIRV::Capability::Kernel);
1010bdd1243dSDimitry Andric       Reqs.addCapability(SPIRV::Capability::GroupNonUniformArithmetic);
1011bdd1243dSDimitry Andric       Reqs.addCapability(SPIRV::Capability::GroupNonUniformBallot);
1012bdd1243dSDimitry Andric       break;
1013bdd1243dSDimitry Andric     case SPIRV::GroupOperation::ClusteredReduce:
1014bdd1243dSDimitry Andric       Reqs.addCapability(SPIRV::Capability::GroupNonUniformClustered);
1015bdd1243dSDimitry Andric       break;
1016bdd1243dSDimitry Andric     case SPIRV::GroupOperation::PartitionedReduceNV:
1017bdd1243dSDimitry Andric     case SPIRV::GroupOperation::PartitionedInclusiveScanNV:
1018bdd1243dSDimitry Andric     case SPIRV::GroupOperation::PartitionedExclusiveScanNV:
1019bdd1243dSDimitry Andric       Reqs.addCapability(SPIRV::Capability::GroupNonUniformPartitionedNV);
1020bdd1243dSDimitry Andric       break;
1021bdd1243dSDimitry Andric     }
1022bdd1243dSDimitry Andric     break;
1023bdd1243dSDimitry Andric   }
1024bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformShuffle:
1025bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformShuffleXor:
1026bdd1243dSDimitry Andric     Reqs.addCapability(SPIRV::Capability::GroupNonUniformShuffle);
1027bdd1243dSDimitry Andric     break;
1028bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformShuffleUp:
1029bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformShuffleDown:
1030bdd1243dSDimitry Andric     Reqs.addCapability(SPIRV::Capability::GroupNonUniformShuffleRelative);
1031bdd1243dSDimitry Andric     break;
1032bdd1243dSDimitry Andric   case SPIRV::OpGroupAll:
1033bdd1243dSDimitry Andric   case SPIRV::OpGroupAny:
1034bdd1243dSDimitry Andric   case SPIRV::OpGroupBroadcast:
1035bdd1243dSDimitry Andric   case SPIRV::OpGroupIAdd:
1036bdd1243dSDimitry Andric   case SPIRV::OpGroupFAdd:
1037bdd1243dSDimitry Andric   case SPIRV::OpGroupFMin:
1038bdd1243dSDimitry Andric   case SPIRV::OpGroupUMin:
1039bdd1243dSDimitry Andric   case SPIRV::OpGroupSMin:
1040bdd1243dSDimitry Andric   case SPIRV::OpGroupFMax:
1041bdd1243dSDimitry Andric   case SPIRV::OpGroupUMax:
1042bdd1243dSDimitry Andric   case SPIRV::OpGroupSMax:
1043bdd1243dSDimitry Andric     Reqs.addCapability(SPIRV::Capability::Groups);
1044bdd1243dSDimitry Andric     break;
1045bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformElect:
1046bdd1243dSDimitry Andric     Reqs.addCapability(SPIRV::Capability::GroupNonUniform);
1047bdd1243dSDimitry Andric     break;
1048bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformAll:
1049bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformAny:
1050bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformAllEqual:
1051bdd1243dSDimitry Andric     Reqs.addCapability(SPIRV::Capability::GroupNonUniformVote);
1052bdd1243dSDimitry Andric     break;
1053bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformBroadcast:
1054bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformBroadcastFirst:
1055bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformBallot:
1056bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformInverseBallot:
1057bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformBallotBitExtract:
1058bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformBallotBitCount:
1059bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformBallotFindLSB:
1060bdd1243dSDimitry Andric   case SPIRV::OpGroupNonUniformBallotFindMSB:
1061bdd1243dSDimitry Andric     Reqs.addCapability(SPIRV::Capability::GroupNonUniformBallot);
1062bdd1243dSDimitry Andric     break;
1063*0fca6ea1SDimitry Andric   case SPIRV::OpSubgroupShuffleINTEL:
1064*0fca6ea1SDimitry Andric   case SPIRV::OpSubgroupShuffleDownINTEL:
1065*0fca6ea1SDimitry Andric   case SPIRV::OpSubgroupShuffleUpINTEL:
1066*0fca6ea1SDimitry Andric   case SPIRV::OpSubgroupShuffleXorINTEL:
1067*0fca6ea1SDimitry Andric     if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
1068*0fca6ea1SDimitry Andric       Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
1069*0fca6ea1SDimitry Andric       Reqs.addCapability(SPIRV::Capability::SubgroupShuffleINTEL);
1070*0fca6ea1SDimitry Andric     }
1071*0fca6ea1SDimitry Andric     break;
1072*0fca6ea1SDimitry Andric   case SPIRV::OpSubgroupBlockReadINTEL:
1073*0fca6ea1SDimitry Andric   case SPIRV::OpSubgroupBlockWriteINTEL:
1074*0fca6ea1SDimitry Andric     if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
1075*0fca6ea1SDimitry Andric       Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
1076*0fca6ea1SDimitry Andric       Reqs.addCapability(SPIRV::Capability::SubgroupBufferBlockIOINTEL);
1077*0fca6ea1SDimitry Andric     }
1078*0fca6ea1SDimitry Andric     break;
1079*0fca6ea1SDimitry Andric   case SPIRV::OpSubgroupImageBlockReadINTEL:
1080*0fca6ea1SDimitry Andric   case SPIRV::OpSubgroupImageBlockWriteINTEL:
1081*0fca6ea1SDimitry Andric     if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
1082*0fca6ea1SDimitry Andric       Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
1083*0fca6ea1SDimitry Andric       Reqs.addCapability(SPIRV::Capability::SubgroupImageBlockIOINTEL);
1084*0fca6ea1SDimitry Andric     }
1085*0fca6ea1SDimitry Andric     break;
10865f757f3fSDimitry Andric   case SPIRV::OpAssumeTrueKHR:
10875f757f3fSDimitry Andric   case SPIRV::OpExpectKHR:
10885f757f3fSDimitry Andric     if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) {
10895f757f3fSDimitry Andric       Reqs.addExtension(SPIRV::Extension::SPV_KHR_expect_assume);
10905f757f3fSDimitry Andric       Reqs.addCapability(SPIRV::Capability::ExpectAssumeKHR);
10915f757f3fSDimitry Andric     }
10925f757f3fSDimitry Andric     break;
1093*0fca6ea1SDimitry Andric   case SPIRV::OpPtrCastToCrossWorkgroupINTEL:
1094*0fca6ea1SDimitry Andric   case SPIRV::OpCrossWorkgroupCastToPtrINTEL:
1095*0fca6ea1SDimitry Andric     if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes)) {
1096*0fca6ea1SDimitry Andric       Reqs.addExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes);
1097*0fca6ea1SDimitry Andric       Reqs.addCapability(SPIRV::Capability::USMStorageClassesINTEL);
1098*0fca6ea1SDimitry Andric     }
1099*0fca6ea1SDimitry Andric     break;
1100*0fca6ea1SDimitry Andric   case SPIRV::OpConstantFunctionPointerINTEL:
1101*0fca6ea1SDimitry Andric     if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)) {
1102*0fca6ea1SDimitry Andric       Reqs.addExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
1103*0fca6ea1SDimitry Andric       Reqs.addCapability(SPIRV::Capability::FunctionPointersINTEL);
1104*0fca6ea1SDimitry Andric     }
1105*0fca6ea1SDimitry Andric     break;
1106*0fca6ea1SDimitry Andric   case SPIRV::OpGroupNonUniformRotateKHR:
1107*0fca6ea1SDimitry Andric     if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_subgroup_rotate))
1108*0fca6ea1SDimitry Andric       report_fatal_error("OpGroupNonUniformRotateKHR instruction requires the "
1109*0fca6ea1SDimitry Andric                          "following SPIR-V extension: SPV_KHR_subgroup_rotate",
1110*0fca6ea1SDimitry Andric                          false);
1111*0fca6ea1SDimitry Andric     Reqs.addExtension(SPIRV::Extension::SPV_KHR_subgroup_rotate);
1112*0fca6ea1SDimitry Andric     Reqs.addCapability(SPIRV::Capability::GroupNonUniformRotateKHR);
1113*0fca6ea1SDimitry Andric     Reqs.addCapability(SPIRV::Capability::GroupNonUniform);
1114*0fca6ea1SDimitry Andric     break;
1115*0fca6ea1SDimitry Andric   case SPIRV::OpGroupIMulKHR:
1116*0fca6ea1SDimitry Andric   case SPIRV::OpGroupFMulKHR:
1117*0fca6ea1SDimitry Andric   case SPIRV::OpGroupBitwiseAndKHR:
1118*0fca6ea1SDimitry Andric   case SPIRV::OpGroupBitwiseOrKHR:
1119*0fca6ea1SDimitry Andric   case SPIRV::OpGroupBitwiseXorKHR:
1120*0fca6ea1SDimitry Andric   case SPIRV::OpGroupLogicalAndKHR:
1121*0fca6ea1SDimitry Andric   case SPIRV::OpGroupLogicalOrKHR:
1122*0fca6ea1SDimitry Andric   case SPIRV::OpGroupLogicalXorKHR:
1123*0fca6ea1SDimitry Andric     if (ST.canUseExtension(
1124*0fca6ea1SDimitry Andric             SPIRV::Extension::SPV_KHR_uniform_group_instructions)) {
1125*0fca6ea1SDimitry Andric       Reqs.addExtension(SPIRV::Extension::SPV_KHR_uniform_group_instructions);
1126*0fca6ea1SDimitry Andric       Reqs.addCapability(SPIRV::Capability::GroupUniformArithmeticKHR);
1127*0fca6ea1SDimitry Andric     }
1128*0fca6ea1SDimitry Andric     break;
1129*0fca6ea1SDimitry Andric   case SPIRV::OpReadClockKHR:
1130*0fca6ea1SDimitry Andric     if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_shader_clock))
1131*0fca6ea1SDimitry Andric       report_fatal_error("OpReadClockKHR instruction requires the "
1132*0fca6ea1SDimitry Andric                          "following SPIR-V extension: SPV_KHR_shader_clock",
1133*0fca6ea1SDimitry Andric                          false);
1134*0fca6ea1SDimitry Andric     Reqs.addExtension(SPIRV::Extension::SPV_KHR_shader_clock);
1135*0fca6ea1SDimitry Andric     Reqs.addCapability(SPIRV::Capability::ShaderClockKHR);
1136*0fca6ea1SDimitry Andric     break;
1137*0fca6ea1SDimitry Andric   case SPIRV::OpFunctionPointerCallINTEL:
1138*0fca6ea1SDimitry Andric     if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)) {
1139*0fca6ea1SDimitry Andric       Reqs.addExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
1140*0fca6ea1SDimitry Andric       Reqs.addCapability(SPIRV::Capability::FunctionPointersINTEL);
1141*0fca6ea1SDimitry Andric     }
1142*0fca6ea1SDimitry Andric     break;
1143*0fca6ea1SDimitry Andric   case SPIRV::OpAtomicFAddEXT:
1144*0fca6ea1SDimitry Andric   case SPIRV::OpAtomicFMinEXT:
1145*0fca6ea1SDimitry Andric   case SPIRV::OpAtomicFMaxEXT:
1146*0fca6ea1SDimitry Andric     AddAtomicFloatRequirements(MI, Reqs, ST);
1147*0fca6ea1SDimitry Andric     break;
1148*0fca6ea1SDimitry Andric   case SPIRV::OpConvertBF16ToFINTEL:
1149*0fca6ea1SDimitry Andric   case SPIRV::OpConvertFToBF16INTEL:
1150*0fca6ea1SDimitry Andric     if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bfloat16_conversion)) {
1151*0fca6ea1SDimitry Andric       Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_conversion);
1152*0fca6ea1SDimitry Andric       Reqs.addCapability(SPIRV::Capability::BFloat16ConversionINTEL);
1153*0fca6ea1SDimitry Andric     }
1154*0fca6ea1SDimitry Andric     break;
1155*0fca6ea1SDimitry Andric   case SPIRV::OpVariableLengthArrayINTEL:
1156*0fca6ea1SDimitry Andric   case SPIRV::OpSaveMemoryINTEL:
1157*0fca6ea1SDimitry Andric   case SPIRV::OpRestoreMemoryINTEL:
1158*0fca6ea1SDimitry Andric     if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array)) {
1159*0fca6ea1SDimitry Andric       Reqs.addExtension(SPIRV::Extension::SPV_INTEL_variable_length_array);
1160*0fca6ea1SDimitry Andric       Reqs.addCapability(SPIRV::Capability::VariableLengthArrayINTEL);
1161*0fca6ea1SDimitry Andric     }
1162*0fca6ea1SDimitry Andric     break;
1163*0fca6ea1SDimitry Andric   case SPIRV::OpAsmTargetINTEL:
1164*0fca6ea1SDimitry Andric   case SPIRV::OpAsmINTEL:
1165*0fca6ea1SDimitry Andric   case SPIRV::OpAsmCallINTEL:
1166*0fca6ea1SDimitry Andric     if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_inline_assembly)) {
1167*0fca6ea1SDimitry Andric       Reqs.addExtension(SPIRV::Extension::SPV_INTEL_inline_assembly);
1168*0fca6ea1SDimitry Andric       Reqs.addCapability(SPIRV::Capability::AsmINTEL);
1169*0fca6ea1SDimitry Andric     }
1170*0fca6ea1SDimitry Andric     break;
1171*0fca6ea1SDimitry Andric   case SPIRV::OpTypeCooperativeMatrixKHR:
1172*0fca6ea1SDimitry Andric     if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix))
1173*0fca6ea1SDimitry Andric       report_fatal_error(
1174*0fca6ea1SDimitry Andric           "OpTypeCooperativeMatrixKHR type requires the "
1175*0fca6ea1SDimitry Andric           "following SPIR-V extension: SPV_KHR_cooperative_matrix",
1176*0fca6ea1SDimitry Andric           false);
1177*0fca6ea1SDimitry Andric     Reqs.addExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix);
1178*0fca6ea1SDimitry Andric     Reqs.addCapability(SPIRV::Capability::CooperativeMatrixKHR);
1179*0fca6ea1SDimitry Andric     break;
1180bdd1243dSDimitry Andric   default:
1181bdd1243dSDimitry Andric     break;
1182bdd1243dSDimitry Andric   }
11835f757f3fSDimitry Andric 
11845f757f3fSDimitry Andric   // If we require capability Shader, then we can remove the requirement for
11855f757f3fSDimitry Andric   // the BitInstructions capability, since Shader is a superset capability
11865f757f3fSDimitry Andric   // of BitInstructions.
11875f757f3fSDimitry Andric   Reqs.removeCapabilityIf(SPIRV::Capability::BitInstructions,
11885f757f3fSDimitry Andric                           SPIRV::Capability::Shader);
1189bdd1243dSDimitry Andric }
1190bdd1243dSDimitry Andric 
1191bdd1243dSDimitry Andric static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI,
1192bdd1243dSDimitry Andric                         MachineModuleInfo *MMI, const SPIRVSubtarget &ST) {
1193bdd1243dSDimitry Andric   // Collect requirements for existing instructions.
1194bdd1243dSDimitry Andric   for (auto F = M.begin(), E = M.end(); F != E; ++F) {
1195bdd1243dSDimitry Andric     MachineFunction *MF = MMI->getMachineFunction(*F);
1196bdd1243dSDimitry Andric     if (!MF)
1197bdd1243dSDimitry Andric       continue;
1198bdd1243dSDimitry Andric     for (const MachineBasicBlock &MBB : *MF)
1199bdd1243dSDimitry Andric       for (const MachineInstr &MI : MBB)
1200bdd1243dSDimitry Andric         addInstrRequirements(MI, MAI.Reqs, ST);
1201bdd1243dSDimitry Andric   }
1202bdd1243dSDimitry Andric   // Collect requirements for OpExecutionMode instructions.
1203bdd1243dSDimitry Andric   auto Node = M.getNamedMetadata("spirv.ExecutionMode");
1204bdd1243dSDimitry Andric   if (Node) {
1205*0fca6ea1SDimitry Andric     // SPV_KHR_float_controls is not available until v1.4
1206*0fca6ea1SDimitry Andric     bool RequireFloatControls = false,
1207*0fca6ea1SDimitry Andric          VerLower14 = !ST.isAtLeastSPIRVVer(VersionTuple(1, 4));
1208bdd1243dSDimitry Andric     for (unsigned i = 0; i < Node->getNumOperands(); i++) {
1209bdd1243dSDimitry Andric       MDNode *MDN = cast<MDNode>(Node->getOperand(i));
1210bdd1243dSDimitry Andric       const MDOperand &MDOp = MDN->getOperand(1);
1211bdd1243dSDimitry Andric       if (auto *CMeta = dyn_cast<ConstantAsMetadata>(MDOp)) {
1212bdd1243dSDimitry Andric         Constant *C = CMeta->getValue();
1213bdd1243dSDimitry Andric         if (ConstantInt *Const = dyn_cast<ConstantInt>(C)) {
1214bdd1243dSDimitry Andric           auto EM = Const->getZExtValue();
1215bdd1243dSDimitry Andric           MAI.Reqs.getAndAddRequirements(
1216bdd1243dSDimitry Andric               SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
1217*0fca6ea1SDimitry Andric           // add SPV_KHR_float_controls if the version is too low
1218*0fca6ea1SDimitry Andric           switch (EM) {
1219*0fca6ea1SDimitry Andric           case SPIRV::ExecutionMode::DenormPreserve:
1220*0fca6ea1SDimitry Andric           case SPIRV::ExecutionMode::DenormFlushToZero:
1221*0fca6ea1SDimitry Andric           case SPIRV::ExecutionMode::SignedZeroInfNanPreserve:
1222*0fca6ea1SDimitry Andric           case SPIRV::ExecutionMode::RoundingModeRTE:
1223*0fca6ea1SDimitry Andric           case SPIRV::ExecutionMode::RoundingModeRTZ:
1224*0fca6ea1SDimitry Andric             RequireFloatControls = VerLower14;
1225*0fca6ea1SDimitry Andric             break;
1226bdd1243dSDimitry Andric           }
1227bdd1243dSDimitry Andric         }
1228bdd1243dSDimitry Andric       }
1229bdd1243dSDimitry Andric     }
1230*0fca6ea1SDimitry Andric     if (RequireFloatControls &&
1231*0fca6ea1SDimitry Andric         ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls))
1232*0fca6ea1SDimitry Andric       MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls);
1233*0fca6ea1SDimitry Andric   }
1234bdd1243dSDimitry Andric   for (auto FI = M.begin(), E = M.end(); FI != E; ++FI) {
1235bdd1243dSDimitry Andric     const Function &F = *FI;
1236bdd1243dSDimitry Andric     if (F.isDeclaration())
1237bdd1243dSDimitry Andric       continue;
1238bdd1243dSDimitry Andric     if (F.getMetadata("reqd_work_group_size"))
1239bdd1243dSDimitry Andric       MAI.Reqs.getAndAddRequirements(
1240bdd1243dSDimitry Andric           SPIRV::OperandCategory::ExecutionModeOperand,
1241bdd1243dSDimitry Andric           SPIRV::ExecutionMode::LocalSize, ST);
12425f757f3fSDimitry Andric     if (F.getFnAttribute("hlsl.numthreads").isValid()) {
12435f757f3fSDimitry Andric       MAI.Reqs.getAndAddRequirements(
12445f757f3fSDimitry Andric           SPIRV::OperandCategory::ExecutionModeOperand,
12455f757f3fSDimitry Andric           SPIRV::ExecutionMode::LocalSize, ST);
12465f757f3fSDimitry Andric     }
1247bdd1243dSDimitry Andric     if (F.getMetadata("work_group_size_hint"))
1248bdd1243dSDimitry Andric       MAI.Reqs.getAndAddRequirements(
1249bdd1243dSDimitry Andric           SPIRV::OperandCategory::ExecutionModeOperand,
1250bdd1243dSDimitry Andric           SPIRV::ExecutionMode::LocalSizeHint, ST);
1251bdd1243dSDimitry Andric     if (F.getMetadata("intel_reqd_sub_group_size"))
1252bdd1243dSDimitry Andric       MAI.Reqs.getAndAddRequirements(
1253bdd1243dSDimitry Andric           SPIRV::OperandCategory::ExecutionModeOperand,
1254bdd1243dSDimitry Andric           SPIRV::ExecutionMode::SubgroupSize, ST);
1255bdd1243dSDimitry Andric     if (F.getMetadata("vec_type_hint"))
1256bdd1243dSDimitry Andric       MAI.Reqs.getAndAddRequirements(
1257bdd1243dSDimitry Andric           SPIRV::OperandCategory::ExecutionModeOperand,
1258bdd1243dSDimitry Andric           SPIRV::ExecutionMode::VecTypeHint, ST);
12595f757f3fSDimitry Andric 
12605f757f3fSDimitry Andric     if (F.hasOptNone() &&
12615f757f3fSDimitry Andric         ST.canUseExtension(SPIRV::Extension::SPV_INTEL_optnone)) {
12625f757f3fSDimitry Andric       // Output OpCapability OptNoneINTEL.
12635f757f3fSDimitry Andric       MAI.Reqs.addExtension(SPIRV::Extension::SPV_INTEL_optnone);
12645f757f3fSDimitry Andric       MAI.Reqs.addCapability(SPIRV::Capability::OptNoneINTEL);
12655f757f3fSDimitry Andric     }
1266bdd1243dSDimitry Andric   }
1267bdd1243dSDimitry Andric }
1268bdd1243dSDimitry Andric 
1269bdd1243dSDimitry Andric static unsigned getFastMathFlags(const MachineInstr &I) {
1270bdd1243dSDimitry Andric   unsigned Flags = SPIRV::FPFastMathMode::None;
1271bdd1243dSDimitry Andric   if (I.getFlag(MachineInstr::MIFlag::FmNoNans))
1272bdd1243dSDimitry Andric     Flags |= SPIRV::FPFastMathMode::NotNaN;
1273bdd1243dSDimitry Andric   if (I.getFlag(MachineInstr::MIFlag::FmNoInfs))
1274bdd1243dSDimitry Andric     Flags |= SPIRV::FPFastMathMode::NotInf;
1275bdd1243dSDimitry Andric   if (I.getFlag(MachineInstr::MIFlag::FmNsz))
1276bdd1243dSDimitry Andric     Flags |= SPIRV::FPFastMathMode::NSZ;
1277bdd1243dSDimitry Andric   if (I.getFlag(MachineInstr::MIFlag::FmArcp))
1278bdd1243dSDimitry Andric     Flags |= SPIRV::FPFastMathMode::AllowRecip;
1279bdd1243dSDimitry Andric   if (I.getFlag(MachineInstr::MIFlag::FmReassoc))
1280bdd1243dSDimitry Andric     Flags |= SPIRV::FPFastMathMode::Fast;
1281bdd1243dSDimitry Andric   return Flags;
1282bdd1243dSDimitry Andric }
1283bdd1243dSDimitry Andric 
1284bdd1243dSDimitry Andric static void handleMIFlagDecoration(MachineInstr &I, const SPIRVSubtarget &ST,
1285bdd1243dSDimitry Andric                                    const SPIRVInstrInfo &TII,
1286bdd1243dSDimitry Andric                                    SPIRV::RequirementHandler &Reqs) {
1287bdd1243dSDimitry Andric   if (I.getFlag(MachineInstr::MIFlag::NoSWrap) && TII.canUseNSW(I) &&
1288bdd1243dSDimitry Andric       getSymbolicOperandRequirements(SPIRV::OperandCategory::DecorationOperand,
1289bdd1243dSDimitry Andric                                      SPIRV::Decoration::NoSignedWrap, ST, Reqs)
1290bdd1243dSDimitry Andric           .IsSatisfiable) {
1291bdd1243dSDimitry Andric     buildOpDecorate(I.getOperand(0).getReg(), I, TII,
1292bdd1243dSDimitry Andric                     SPIRV::Decoration::NoSignedWrap, {});
1293bdd1243dSDimitry Andric   }
1294bdd1243dSDimitry Andric   if (I.getFlag(MachineInstr::MIFlag::NoUWrap) && TII.canUseNUW(I) &&
1295bdd1243dSDimitry Andric       getSymbolicOperandRequirements(SPIRV::OperandCategory::DecorationOperand,
1296bdd1243dSDimitry Andric                                      SPIRV::Decoration::NoUnsignedWrap, ST,
1297bdd1243dSDimitry Andric                                      Reqs)
1298bdd1243dSDimitry Andric           .IsSatisfiable) {
1299bdd1243dSDimitry Andric     buildOpDecorate(I.getOperand(0).getReg(), I, TII,
1300bdd1243dSDimitry Andric                     SPIRV::Decoration::NoUnsignedWrap, {});
1301bdd1243dSDimitry Andric   }
1302bdd1243dSDimitry Andric   if (!TII.canUseFastMathFlags(I))
1303bdd1243dSDimitry Andric     return;
1304bdd1243dSDimitry Andric   unsigned FMFlags = getFastMathFlags(I);
1305bdd1243dSDimitry Andric   if (FMFlags == SPIRV::FPFastMathMode::None)
1306bdd1243dSDimitry Andric     return;
1307bdd1243dSDimitry Andric   Register DstReg = I.getOperand(0).getReg();
1308bdd1243dSDimitry Andric   buildOpDecorate(DstReg, I, TII, SPIRV::Decoration::FPFastMathMode, {FMFlags});
1309bdd1243dSDimitry Andric }
1310bdd1243dSDimitry Andric 
1311bdd1243dSDimitry Andric // Walk all functions and add decorations related to MI flags.
1312bdd1243dSDimitry Andric static void addDecorations(const Module &M, const SPIRVInstrInfo &TII,
1313bdd1243dSDimitry Andric                            MachineModuleInfo *MMI, const SPIRVSubtarget &ST,
1314bdd1243dSDimitry Andric                            SPIRV::ModuleAnalysisInfo &MAI) {
1315bdd1243dSDimitry Andric   for (auto F = M.begin(), E = M.end(); F != E; ++F) {
1316bdd1243dSDimitry Andric     MachineFunction *MF = MMI->getMachineFunction(*F);
1317bdd1243dSDimitry Andric     if (!MF)
1318bdd1243dSDimitry Andric       continue;
1319bdd1243dSDimitry Andric     for (auto &MBB : *MF)
1320bdd1243dSDimitry Andric       for (auto &MI : MBB)
1321bdd1243dSDimitry Andric         handleMIFlagDecoration(MI, ST, TII, MAI.Reqs);
1322bdd1243dSDimitry Andric   }
1323bdd1243dSDimitry Andric }
1324bdd1243dSDimitry Andric 
132581ad6265SDimitry Andric struct SPIRV::ModuleAnalysisInfo SPIRVModuleAnalysis::MAI;
132681ad6265SDimitry Andric 
132781ad6265SDimitry Andric void SPIRVModuleAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
132881ad6265SDimitry Andric   AU.addRequired<TargetPassConfig>();
132981ad6265SDimitry Andric   AU.addRequired<MachineModuleInfoWrapperPass>();
133081ad6265SDimitry Andric }
133181ad6265SDimitry Andric 
133281ad6265SDimitry Andric bool SPIRVModuleAnalysis::runOnModule(Module &M) {
133381ad6265SDimitry Andric   SPIRVTargetMachine &TM =
133481ad6265SDimitry Andric       getAnalysis<TargetPassConfig>().getTM<SPIRVTargetMachine>();
133581ad6265SDimitry Andric   ST = TM.getSubtargetImpl();
133681ad6265SDimitry Andric   GR = ST->getSPIRVGlobalRegistry();
133781ad6265SDimitry Andric   TII = ST->getInstrInfo();
133881ad6265SDimitry Andric 
133981ad6265SDimitry Andric   MMI = &getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
134081ad6265SDimitry Andric 
134181ad6265SDimitry Andric   setBaseInfo(M);
134281ad6265SDimitry Andric 
1343bdd1243dSDimitry Andric   addDecorations(M, *TII, MMI, *ST, MAI);
1344bdd1243dSDimitry Andric 
1345bdd1243dSDimitry Andric   collectReqs(M, MAI, MMI, *ST);
1346bdd1243dSDimitry Andric 
1347fcaf7f86SDimitry Andric   // Process type/const/global var/func decl instructions, number their
134881ad6265SDimitry Andric   // destination registers from 0 to N, collect Extensions and Capabilities.
1349753f127fSDimitry Andric   processDefInstrs(M);
135081ad6265SDimitry Andric 
135181ad6265SDimitry Andric   // Number rest of registers from N+1 onwards.
135281ad6265SDimitry Andric   numberRegistersGlobally(M);
135381ad6265SDimitry Andric 
1354*0fca6ea1SDimitry Andric   // Update references to OpFunction instructions to use Global Registers
1355*0fca6ea1SDimitry Andric   if (GR->hasConstFunPtr())
1356*0fca6ea1SDimitry Andric     collectFuncPtrs();
1357*0fca6ea1SDimitry Andric 
135881ad6265SDimitry Andric   // Collect OpName, OpEntryPoint, OpDecorate etc, process other instructions.
135981ad6265SDimitry Andric   processOtherInstrs(M);
136081ad6265SDimitry Andric 
1361bdd1243dSDimitry Andric   // If there are no entry points, we need the Linkage capability.
1362bdd1243dSDimitry Andric   if (MAI.MS[SPIRV::MB_EntryPoints].empty())
1363bdd1243dSDimitry Andric     MAI.Reqs.addCapability(SPIRV::Capability::Linkage);
1364bdd1243dSDimitry Andric 
1365*0fca6ea1SDimitry Andric   // Set maximum ID used.
1366*0fca6ea1SDimitry Andric   GR->setBound(MAI.MaxID);
1367*0fca6ea1SDimitry Andric 
136881ad6265SDimitry Andric   return false;
136981ad6265SDimitry Andric }
1370