LLVM 22.0.0git
SPIRVModuleAnalysis.cpp
Go to the documentation of this file.
1//===- SPIRVModuleAnalysis.cpp - analysis of global instrs & regs - C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// The analysis collects instructions that should be output at the module level
10// and performs the global register numbering.
11//
12// The results of this analysis are used in AsmPrinter to rename registers
13// globally and to output required instructions at the module level.
14//
15//===----------------------------------------------------------------------===//
16
17#include "SPIRVModuleAnalysis.h"
20#include "SPIRV.h"
21#include "SPIRVSubtarget.h"
22#include "SPIRVTargetMachine.h"
23#include "SPIRVUtils.h"
24#include "llvm/ADT/STLExtras.h"
27
28using namespace llvm;
29
30#define DEBUG_TYPE "spirv-module-analysis"
31
32static cl::opt<bool>
33 SPVDumpDeps("spv-dump-deps",
34 cl::desc("Dump MIR with SPIR-V dependencies info"),
35 cl::Optional, cl::init(false));
36
38 AvoidCapabilities("avoid-spirv-capabilities",
39 cl::desc("SPIR-V capabilities to avoid if there are "
40 "other options enabling a feature"),
42 cl::values(clEnumValN(SPIRV::Capability::Shader, "Shader",
43 "SPIR-V Shader capability")));
44// Use sets instead of cl::list to check "if contains" condition
49
51
52INITIALIZE_PASS(SPIRVModuleAnalysis, DEBUG_TYPE, "SPIRV module analysis", true,
53 true)
54
55// Retrieve an unsigned from an MDNode with a list of them as operands.
56static unsigned getMetadataUInt(MDNode *MdNode, unsigned OpIndex,
57 unsigned DefaultVal = 0) {
58 if (MdNode && OpIndex < MdNode->getNumOperands()) {
59 const auto &Op = MdNode->getOperand(OpIndex);
60 return mdconst::extract<ConstantInt>(Op)->getZExtValue();
61 }
62 return DefaultVal;
63}
64
66getSymbolicOperandRequirements(SPIRV::OperandCategory::OperandCategory Category,
67 unsigned i, const SPIRVSubtarget &ST,
69 // A set of capabilities to avoid if there is another option.
70 AvoidCapabilitiesSet AvoidCaps;
71 if (!ST.isShader())
72 AvoidCaps.S.insert(SPIRV::Capability::Shader);
73 else
74 AvoidCaps.S.insert(SPIRV::Capability::Kernel);
75
76 VersionTuple ReqMinVer = getSymbolicOperandMinVersion(Category, i);
77 VersionTuple ReqMaxVer = getSymbolicOperandMaxVersion(Category, i);
78 VersionTuple SPIRVVersion = ST.getSPIRVVersion();
79 bool MinVerOK = SPIRVVersion.empty() || SPIRVVersion >= ReqMinVer;
80 bool MaxVerOK =
81 ReqMaxVer.empty() || SPIRVVersion.empty() || SPIRVVersion <= ReqMaxVer;
83 ExtensionList ReqExts = getSymbolicOperandExtensions(Category, i);
84 if (ReqCaps.empty()) {
85 if (ReqExts.empty()) {
86 if (MinVerOK && MaxVerOK)
87 return {true, {}, {}, ReqMinVer, ReqMaxVer};
88 return {false, {}, {}, VersionTuple(), VersionTuple()};
89 }
90 } else if (MinVerOK && MaxVerOK) {
91 if (ReqCaps.size() == 1) {
92 auto Cap = ReqCaps[0];
93 if (Reqs.isCapabilityAvailable(Cap)) {
95 SPIRV::OperandCategory::CapabilityOperand, Cap));
96 return {true, {Cap}, std::move(ReqExts), ReqMinVer, ReqMaxVer};
97 }
98 } else {
99 // By SPIR-V specification: "If an instruction, enumerant, or other
100 // feature specifies multiple enabling capabilities, only one such
101 // capability needs to be declared to use the feature." However, one
102 // capability may be preferred over another. We use command line
103 // argument(s) and AvoidCapabilities to avoid selection of certain
104 // capabilities if there are other options.
105 CapabilityList UseCaps;
106 for (auto Cap : ReqCaps)
107 if (Reqs.isCapabilityAvailable(Cap))
108 UseCaps.push_back(Cap);
109 for (size_t i = 0, Sz = UseCaps.size(); i < Sz; ++i) {
110 auto Cap = UseCaps[i];
111 if (i == Sz - 1 || !AvoidCaps.S.contains(Cap)) {
113 SPIRV::OperandCategory::CapabilityOperand, Cap));
114 return {true, {Cap}, std::move(ReqExts), ReqMinVer, ReqMaxVer};
115 }
116 }
117 }
118 }
119 // If there are no capabilities, or we can't satisfy the version or
120 // capability requirements, use the list of extensions (if the subtarget
121 // can handle them all).
122 if (llvm::all_of(ReqExts, [&ST](const SPIRV::Extension::Extension &Ext) {
123 return ST.canUseExtension(Ext);
124 })) {
125 return {true,
126 {},
127 std::move(ReqExts),
128 VersionTuple(),
129 VersionTuple()}; // TODO: add versions to extensions.
130 }
131 return {false, {}, {}, VersionTuple(), VersionTuple()};
132}
133
134void SPIRVModuleAnalysis::setBaseInfo(const Module &M) {
135 MAI.MaxID = 0;
136 for (int i = 0; i < SPIRV::NUM_MODULE_SECTIONS; i++)
137 MAI.MS[i].clear();
138 MAI.RegisterAliasTable.clear();
139 MAI.InstrsToDelete.clear();
140 MAI.FuncMap.clear();
141 MAI.GlobalVarList.clear();
142 MAI.ExtInstSetMap.clear();
143 MAI.Reqs.clear();
144 MAI.Reqs.initAvailableCapabilities(*ST);
145
146 // TODO: determine memory model and source language from the configuratoin.
147 if (auto MemModel = M.getNamedMetadata("spirv.MemoryModel")) {
148 auto MemMD = MemModel->getOperand(0);
149 MAI.Addr = static_cast<SPIRV::AddressingModel::AddressingModel>(
150 getMetadataUInt(MemMD, 0));
151 MAI.Mem =
152 static_cast<SPIRV::MemoryModel::MemoryModel>(getMetadataUInt(MemMD, 1));
153 } else {
154 // TODO: Add support for VulkanMemoryModel.
155 MAI.Mem = ST->isShader() ? SPIRV::MemoryModel::GLSL450
156 : SPIRV::MemoryModel::OpenCL;
157 if (MAI.Mem == SPIRV::MemoryModel::OpenCL) {
158 unsigned PtrSize = ST->getPointerSize();
159 MAI.Addr = PtrSize == 32 ? SPIRV::AddressingModel::Physical32
160 : PtrSize == 64 ? SPIRV::AddressingModel::Physical64
161 : SPIRV::AddressingModel::Logical;
162 } else {
163 // TODO: Add support for PhysicalStorageBufferAddress.
164 MAI.Addr = SPIRV::AddressingModel::Logical;
165 }
166 }
167 // Get the OpenCL version number from metadata.
168 // TODO: support other source languages.
169 if (auto VerNode = M.getNamedMetadata("opencl.ocl.version")) {
170 MAI.SrcLang = SPIRV::SourceLanguage::OpenCL_C;
171 // Construct version literal in accordance with SPIRV-LLVM-Translator.
172 // TODO: support multiple OCL version metadata.
173 assert(VerNode->getNumOperands() > 0 && "Invalid SPIR");
174 auto VersionMD = VerNode->getOperand(0);
175 unsigned MajorNum = getMetadataUInt(VersionMD, 0, 2);
176 unsigned MinorNum = getMetadataUInt(VersionMD, 1);
177 unsigned RevNum = getMetadataUInt(VersionMD, 2);
178 // Prevent Major part of OpenCL version to be 0
179 MAI.SrcLangVersion =
180 (std::max(1U, MajorNum) * 100 + MinorNum) * 1000 + RevNum;
181 } else {
182 // If there is no information about OpenCL version we are forced to generate
183 // OpenCL 1.0 by default for the OpenCL environment to avoid puzzling
184 // run-times with Unknown/0.0 version output. For a reference, LLVM-SPIRV
185 // Translator avoids potential issues with run-times in a similar manner.
186 if (!ST->isShader()) {
187 MAI.SrcLang = SPIRV::SourceLanguage::OpenCL_CPP;
188 MAI.SrcLangVersion = 100000;
189 } else {
190 MAI.SrcLang = SPIRV::SourceLanguage::Unknown;
191 MAI.SrcLangVersion = 0;
192 }
193 }
194
195 if (auto ExtNode = M.getNamedMetadata("opencl.used.extensions")) {
196 for (unsigned I = 0, E = ExtNode->getNumOperands(); I != E; ++I) {
197 MDNode *MD = ExtNode->getOperand(I);
198 if (!MD || MD->getNumOperands() == 0)
199 continue;
200 for (unsigned J = 0, N = MD->getNumOperands(); J != N; ++J)
201 MAI.SrcExt.insert(cast<MDString>(MD->getOperand(J))->getString());
202 }
203 }
204
205 // Update required capabilities for this memory model, addressing model and
206 // source language.
207 MAI.Reqs.getAndAddRequirements(SPIRV::OperandCategory::MemoryModelOperand,
208 MAI.Mem, *ST);
209 MAI.Reqs.getAndAddRequirements(SPIRV::OperandCategory::SourceLanguageOperand,
210 MAI.SrcLang, *ST);
211 MAI.Reqs.getAndAddRequirements(SPIRV::OperandCategory::AddressingModelOperand,
212 MAI.Addr, *ST);
213
214 if (!ST->isShader()) {
215 // TODO: check if it's required by default.
216 MAI.ExtInstSetMap[static_cast<unsigned>(
217 SPIRV::InstructionSet::OpenCL_std)] = MAI.getNextIDRegister();
218 }
219}
220
221// Appends the signature of the decoration instructions that decorate R to
222// Signature.
223static void appendDecorationsForReg(const MachineRegisterInfo &MRI, Register R,
224 InstrSignature &Signature) {
225 for (MachineInstr &UseMI : MRI.use_instructions(R)) {
226 // We don't handle OpDecorateId because getting the register alias for the
227 // ID can cause problems, and we do not need it for now.
228 if (UseMI.getOpcode() != SPIRV::OpDecorate &&
229 UseMI.getOpcode() != SPIRV::OpMemberDecorate)
230 continue;
231
232 for (unsigned I = 0; I < UseMI.getNumOperands(); ++I) {
233 const MachineOperand &MO = UseMI.getOperand(I);
234 if (MO.isReg())
235 continue;
236 Signature.push_back(hash_value(MO));
237 }
238 }
239}
240
241// Returns a representation of an instruction as a vector of MachineOperand
242// hash values, see llvm::hash_value(const MachineOperand &MO) for details.
243// This creates a signature of the instruction with the same content
244// that MachineOperand::isIdenticalTo uses for comparison.
245static InstrSignature instrToSignature(const MachineInstr &MI,
247 bool UseDefReg) {
248 Register DefReg;
249 InstrSignature Signature{MI.getOpcode()};
250 for (unsigned i = 0; i < MI.getNumOperands(); ++i) {
251 const MachineOperand &MO = MI.getOperand(i);
252 size_t h;
253 if (MO.isReg()) {
254 if (!UseDefReg && MO.isDef()) {
255 assert(!DefReg.isValid() && "Multiple def registers.");
256 DefReg = MO.getReg();
257 continue;
258 }
259 Register RegAlias = MAI.getRegisterAlias(MI.getMF(), MO.getReg());
260 if (!RegAlias.isValid()) {
261 LLVM_DEBUG({
262 dbgs() << "Unexpectedly, no global id found for the operand ";
263 MO.print(dbgs());
264 dbgs() << "\nInstruction: ";
265 MI.print(dbgs());
266 dbgs() << "\n";
267 });
268 report_fatal_error("All v-regs must have been mapped to global id's");
269 }
270 // mimic llvm::hash_value(const MachineOperand &MO)
271 h = hash_combine(MO.getType(), (unsigned)RegAlias, MO.getSubReg(),
272 MO.isDef());
273 } else {
274 h = hash_value(MO);
275 }
276 Signature.push_back(h);
277 }
278
279 if (DefReg.isValid()) {
280 // Decorations change the semantics of the current instruction. So two
281 // identical instruction with different decorations cannot be merged. That
282 // is why we add the decorations to the signature.
283 appendDecorationsForReg(MI.getMF()->getRegInfo(), DefReg, Signature);
284 }
285 return Signature;
286}
287
288bool SPIRVModuleAnalysis::isDeclSection(const MachineRegisterInfo &MRI,
289 const MachineInstr &MI) {
290 unsigned Opcode = MI.getOpcode();
291 switch (Opcode) {
292 case SPIRV::OpTypeForwardPointer:
293 // omit now, collect later
294 return false;
295 case SPIRV::OpVariable:
296 return static_cast<SPIRV::StorageClass::StorageClass>(
297 MI.getOperand(2).getImm()) != SPIRV::StorageClass::Function;
298 case SPIRV::OpFunction:
299 case SPIRV::OpFunctionParameter:
300 return true;
301 }
302 if (GR->hasConstFunPtr() && Opcode == SPIRV::OpUndef) {
303 Register DefReg = MI.getOperand(0).getReg();
304 for (MachineInstr &UseMI : MRI.use_instructions(DefReg)) {
305 if (UseMI.getOpcode() != SPIRV::OpConstantFunctionPointerINTEL)
306 continue;
307 // it's a dummy definition, FP constant refers to a function,
308 // and this is resolved in another way; let's skip this definition
309 assert(UseMI.getOperand(2).isReg() &&
310 UseMI.getOperand(2).getReg() == DefReg);
311 MAI.setSkipEmission(&MI);
312 return false;
313 }
314 }
315 return TII->isTypeDeclInstr(MI) || TII->isConstantInstr(MI) ||
316 TII->isInlineAsmDefInstr(MI);
317}
318
319// This is a special case of a function pointer refering to a possibly
320// forward function declaration. The operand is a dummy OpUndef that
321// requires a special treatment.
322void SPIRVModuleAnalysis::visitFunPtrUse(
323 Register OpReg, InstrGRegsMap &SignatureToGReg,
324 std::map<const Value *, unsigned> &GlobalToGReg, const MachineFunction *MF,
325 const MachineInstr &MI) {
326 const MachineOperand *OpFunDef =
327 GR->getFunctionDefinitionByUse(&MI.getOperand(2));
328 assert(OpFunDef && OpFunDef->isReg());
329 // find the actual function definition and number it globally in advance
330 const MachineInstr *OpDefMI = OpFunDef->getParent();
331 assert(OpDefMI && OpDefMI->getOpcode() == SPIRV::OpFunction);
332 const MachineFunction *FunDefMF = OpDefMI->getParent()->getParent();
333 const MachineRegisterInfo &FunDefMRI = FunDefMF->getRegInfo();
334 do {
335 visitDecl(FunDefMRI, SignatureToGReg, GlobalToGReg, FunDefMF, *OpDefMI);
336 OpDefMI = OpDefMI->getNextNode();
337 } while (OpDefMI && (OpDefMI->getOpcode() == SPIRV::OpFunction ||
338 OpDefMI->getOpcode() == SPIRV::OpFunctionParameter));
339 // associate the function pointer with the newly assigned global number
340 MCRegister GlobalFunDefReg =
341 MAI.getRegisterAlias(FunDefMF, OpFunDef->getReg());
342 assert(GlobalFunDefReg.isValid() &&
343 "Function definition must refer to a global register");
344 MAI.setRegisterAlias(MF, OpReg, GlobalFunDefReg);
345}
346
347// Depth first recursive traversal of dependencies. Repeated visits are guarded
348// by MAI.hasRegisterAlias().
349void SPIRVModuleAnalysis::visitDecl(
350 const MachineRegisterInfo &MRI, InstrGRegsMap &SignatureToGReg,
351 std::map<const Value *, unsigned> &GlobalToGReg, const MachineFunction *MF,
352 const MachineInstr &MI) {
353 unsigned Opcode = MI.getOpcode();
354
355 // Process each operand of the instruction to resolve dependencies
356 for (const MachineOperand &MO : MI.operands()) {
357 if (!MO.isReg() || MO.isDef())
358 continue;
359 Register OpReg = MO.getReg();
360 // Handle function pointers special case
361 if (Opcode == SPIRV::OpConstantFunctionPointerINTEL &&
362 MRI.getRegClass(OpReg) == &SPIRV::pIDRegClass) {
363 visitFunPtrUse(OpReg, SignatureToGReg, GlobalToGReg, MF, MI);
364 continue;
365 }
366 // Skip already processed instructions
367 if (MAI.hasRegisterAlias(MF, MO.getReg()))
368 continue;
369 // Recursively visit dependencies
370 if (const MachineInstr *OpDefMI = MRI.getUniqueVRegDef(OpReg)) {
371 if (isDeclSection(MRI, *OpDefMI))
372 visitDecl(MRI, SignatureToGReg, GlobalToGReg, MF, *OpDefMI);
373 continue;
374 }
375 // Handle the unexpected case of no unique definition for the SPIR-V
376 // instruction
377 LLVM_DEBUG({
378 dbgs() << "Unexpectedly, no unique definition for the operand ";
379 MO.print(dbgs());
380 dbgs() << "\nInstruction: ";
381 MI.print(dbgs());
382 dbgs() << "\n";
383 });
385 "No unique definition is found for the virtual register");
386 }
387
388 MCRegister GReg;
389 bool IsFunDef = false;
390 if (TII->isSpecConstantInstr(MI)) {
391 GReg = MAI.getNextIDRegister();
392 MAI.MS[SPIRV::MB_TypeConstVars].push_back(&MI);
393 } else if (Opcode == SPIRV::OpFunction ||
394 Opcode == SPIRV::OpFunctionParameter) {
395 GReg = handleFunctionOrParameter(MF, MI, GlobalToGReg, IsFunDef);
396 } else if (Opcode == SPIRV::OpTypeStruct ||
397 Opcode == SPIRV::OpConstantComposite) {
398 GReg = handleTypeDeclOrConstant(MI, SignatureToGReg);
399 const MachineInstr *NextInstr = MI.getNextNode();
400 while (NextInstr &&
401 ((Opcode == SPIRV::OpTypeStruct &&
402 NextInstr->getOpcode() == SPIRV::OpTypeStructContinuedINTEL) ||
403 (Opcode == SPIRV::OpConstantComposite &&
404 NextInstr->getOpcode() ==
405 SPIRV::OpConstantCompositeContinuedINTEL))) {
406 MCRegister Tmp = handleTypeDeclOrConstant(*NextInstr, SignatureToGReg);
407 MAI.setRegisterAlias(MF, NextInstr->getOperand(0).getReg(), Tmp);
408 MAI.setSkipEmission(NextInstr);
409 NextInstr = NextInstr->getNextNode();
410 }
411 } else if (TII->isTypeDeclInstr(MI) || TII->isConstantInstr(MI) ||
412 TII->isInlineAsmDefInstr(MI)) {
413 GReg = handleTypeDeclOrConstant(MI, SignatureToGReg);
414 } else if (Opcode == SPIRV::OpVariable) {
415 GReg = handleVariable(MF, MI, GlobalToGReg);
416 } else {
417 LLVM_DEBUG({
418 dbgs() << "\nInstruction: ";
419 MI.print(dbgs());
420 dbgs() << "\n";
421 });
422 llvm_unreachable("Unexpected instruction is visited");
423 }
424 MAI.setRegisterAlias(MF, MI.getOperand(0).getReg(), GReg);
425 if (!IsFunDef)
426 MAI.setSkipEmission(&MI);
427}
428
429MCRegister SPIRVModuleAnalysis::handleFunctionOrParameter(
430 const MachineFunction *MF, const MachineInstr &MI,
431 std::map<const Value *, unsigned> &GlobalToGReg, bool &IsFunDef) {
432 const Value *GObj = GR->getGlobalObject(MF, MI.getOperand(0).getReg());
433 assert(GObj && "Unregistered global definition");
434 const Function *F = dyn_cast<Function>(GObj);
435 if (!F)
436 F = dyn_cast<Argument>(GObj)->getParent();
437 assert(F && "Expected a reference to a function or an argument");
438 IsFunDef = !F->isDeclaration();
439 auto [It, Inserted] = GlobalToGReg.try_emplace(GObj);
440 if (!Inserted)
441 return It->second;
442 MCRegister GReg = MAI.getNextIDRegister();
443 It->second = GReg;
444 if (!IsFunDef)
445 MAI.MS[SPIRV::MB_ExtFuncDecls].push_back(&MI);
446 return GReg;
447}
448
450SPIRVModuleAnalysis::handleTypeDeclOrConstant(const MachineInstr &MI,
451 InstrGRegsMap &SignatureToGReg) {
452 InstrSignature MISign = instrToSignature(MI, MAI, false);
453 auto [It, Inserted] = SignatureToGReg.try_emplace(MISign);
454 if (!Inserted)
455 return It->second;
456 MCRegister GReg = MAI.getNextIDRegister();
457 It->second = GReg;
458 MAI.MS[SPIRV::MB_TypeConstVars].push_back(&MI);
459 return GReg;
460}
461
462MCRegister SPIRVModuleAnalysis::handleVariable(
463 const MachineFunction *MF, const MachineInstr &MI,
464 std::map<const Value *, unsigned> &GlobalToGReg) {
465 MAI.GlobalVarList.push_back(&MI);
466 const Value *GObj = GR->getGlobalObject(MF, MI.getOperand(0).getReg());
467 assert(GObj && "Unregistered global definition");
468 auto [It, Inserted] = GlobalToGReg.try_emplace(GObj);
469 if (!Inserted)
470 return It->second;
471 MCRegister GReg = MAI.getNextIDRegister();
472 It->second = GReg;
473 MAI.MS[SPIRV::MB_TypeConstVars].push_back(&MI);
474 return GReg;
475}
476
477void SPIRVModuleAnalysis::collectDeclarations(const Module &M) {
478 InstrGRegsMap SignatureToGReg;
479 std::map<const Value *, unsigned> GlobalToGReg;
480 for (auto F = M.begin(), E = M.end(); F != E; ++F) {
481 MachineFunction *MF = MMI->getMachineFunction(*F);
482 if (!MF)
483 continue;
484 const MachineRegisterInfo &MRI = MF->getRegInfo();
485 unsigned PastHeader = 0;
486 for (MachineBasicBlock &MBB : *MF) {
487 for (MachineInstr &MI : MBB) {
488 if (MI.getNumOperands() == 0)
489 continue;
490 unsigned Opcode = MI.getOpcode();
491 if (Opcode == SPIRV::OpFunction) {
492 if (PastHeader == 0) {
493 PastHeader = 1;
494 continue;
495 }
496 } else if (Opcode == SPIRV::OpFunctionParameter) {
497 if (PastHeader < 2)
498 continue;
499 } else if (PastHeader > 0) {
500 PastHeader = 2;
501 }
502
503 const MachineOperand &DefMO = MI.getOperand(0);
504 switch (Opcode) {
505 case SPIRV::OpExtension:
506 MAI.Reqs.addExtension(SPIRV::Extension::Extension(DefMO.getImm()));
507 MAI.setSkipEmission(&MI);
508 break;
509 case SPIRV::OpCapability:
510 MAI.Reqs.addCapability(SPIRV::Capability::Capability(DefMO.getImm()));
511 MAI.setSkipEmission(&MI);
512 if (PastHeader > 0)
513 PastHeader = 2;
514 break;
515 default:
516 if (DefMO.isReg() && isDeclSection(MRI, MI) &&
517 !MAI.hasRegisterAlias(MF, DefMO.getReg()))
518 visitDecl(MRI, SignatureToGReg, GlobalToGReg, MF, MI);
519 }
520 }
521 }
522 }
523}
524
525// Look for IDs declared with Import linkage, and map the corresponding function
526// to the register defining that variable (which will usually be the result of
527// an OpFunction). This lets us call externally imported functions using
528// the correct ID registers.
529void SPIRVModuleAnalysis::collectFuncNames(MachineInstr &MI,
530 const Function *F) {
531 if (MI.getOpcode() == SPIRV::OpDecorate) {
532 // If it's got Import linkage.
533 auto Dec = MI.getOperand(1).getImm();
534 if (Dec == static_cast<unsigned>(SPIRV::Decoration::LinkageAttributes)) {
535 auto Lnk = MI.getOperand(MI.getNumOperands() - 1).getImm();
536 if (Lnk == static_cast<unsigned>(SPIRV::LinkageType::Import)) {
537 // Map imported function name to function ID register.
538 const Function *ImportedFunc =
539 F->getParent()->getFunction(getStringImm(MI, 2));
540 Register Target = MI.getOperand(0).getReg();
541 MAI.FuncMap[ImportedFunc] = MAI.getRegisterAlias(MI.getMF(), Target);
542 }
543 }
544 } else if (MI.getOpcode() == SPIRV::OpFunction) {
545 // Record all internal OpFunction declarations.
546 Register Reg = MI.defs().begin()->getReg();
547 MCRegister GlobalReg = MAI.getRegisterAlias(MI.getMF(), Reg);
548 assert(GlobalReg.isValid());
549 MAI.FuncMap[F] = GlobalReg;
550 }
551}
552
553// Collect the given instruction in the specified MS. We assume global register
554// numbering has already occurred by this point. We can directly compare reg
555// arguments when detecting duplicates.
556static void collectOtherInstr(MachineInstr &MI, SPIRV::ModuleAnalysisInfo &MAI,
558 bool Append = true) {
559 MAI.setSkipEmission(&MI);
560 InstrSignature MISign = instrToSignature(MI, MAI, true);
561 auto FoundMI = IS.insert(std::move(MISign));
562 if (!FoundMI.second)
563 return; // insert failed, so we found a duplicate; don't add it to MAI.MS
564 // No duplicates, so add it.
565 if (Append)
566 MAI.MS[MSType].push_back(&MI);
567 else
568 MAI.MS[MSType].insert(MAI.MS[MSType].begin(), &MI);
569}
570
571// Some global instructions make reference to function-local ID regs, so cannot
572// be correctly collected until these registers are globally numbered.
573void SPIRVModuleAnalysis::processOtherInstrs(const Module &M) {
574 InstrTraces IS;
575 for (auto F = M.begin(), E = M.end(); F != E; ++F) {
576 if ((*F).isDeclaration())
577 continue;
578 MachineFunction *MF = MMI->getMachineFunction(*F);
579 assert(MF);
580
581 for (MachineBasicBlock &MBB : *MF)
582 for (MachineInstr &MI : MBB) {
583 if (MAI.getSkipEmission(&MI))
584 continue;
585 const unsigned OpCode = MI.getOpcode();
586 if (OpCode == SPIRV::OpString) {
587 collectOtherInstr(MI, MAI, SPIRV::MB_DebugStrings, IS);
588 } else if (OpCode == SPIRV::OpExtInst && MI.getOperand(2).isImm() &&
589 MI.getOperand(2).getImm() ==
590 SPIRV::InstructionSet::
591 NonSemantic_Shader_DebugInfo_100) {
592 MachineOperand Ins = MI.getOperand(3);
593 namespace NS = SPIRV::NonSemanticExtInst;
594 static constexpr int64_t GlobalNonSemanticDITy[] = {
595 NS::DebugSource, NS::DebugCompilationUnit, NS::DebugInfoNone,
596 NS::DebugTypeBasic, NS::DebugTypePointer};
597 bool IsGlobalDI = false;
598 for (unsigned Idx = 0; Idx < std::size(GlobalNonSemanticDITy); ++Idx)
599 IsGlobalDI |= Ins.getImm() == GlobalNonSemanticDITy[Idx];
600 if (IsGlobalDI)
601 collectOtherInstr(MI, MAI, SPIRV::MB_NonSemanticGlobalDI, IS);
602 } else if (OpCode == SPIRV::OpName || OpCode == SPIRV::OpMemberName) {
603 collectOtherInstr(MI, MAI, SPIRV::MB_DebugNames, IS);
604 } else if (OpCode == SPIRV::OpEntryPoint) {
605 collectOtherInstr(MI, MAI, SPIRV::MB_EntryPoints, IS);
606 } else if (TII->isAliasingInstr(MI)) {
607 collectOtherInstr(MI, MAI, SPIRV::MB_AliasingInsts, IS);
608 } else if (TII->isDecorationInstr(MI)) {
609 collectOtherInstr(MI, MAI, SPIRV::MB_Annotations, IS);
610 collectFuncNames(MI, &*F);
611 } else if (TII->isConstantInstr(MI)) {
612 // Now OpSpecConstant*s are not in DT,
613 // but they need to be collected anyway.
614 collectOtherInstr(MI, MAI, SPIRV::MB_TypeConstVars, IS);
615 } else if (OpCode == SPIRV::OpFunction) {
616 collectFuncNames(MI, &*F);
617 } else if (OpCode == SPIRV::OpTypeForwardPointer) {
618 collectOtherInstr(MI, MAI, SPIRV::MB_TypeConstVars, IS, false);
619 }
620 }
621 }
622}
623
624// Number registers in all functions globally from 0 onwards and store
625// the result in global register alias table. Some registers are already
626// numbered.
627void SPIRVModuleAnalysis::numberRegistersGlobally(const Module &M) {
628 for (auto F = M.begin(), E = M.end(); F != E; ++F) {
629 if ((*F).isDeclaration())
630 continue;
631 MachineFunction *MF = MMI->getMachineFunction(*F);
632 assert(MF);
633 for (MachineBasicBlock &MBB : *MF) {
634 for (MachineInstr &MI : MBB) {
635 for (MachineOperand &Op : MI.operands()) {
636 if (!Op.isReg())
637 continue;
638 Register Reg = Op.getReg();
639 if (MAI.hasRegisterAlias(MF, Reg))
640 continue;
641 MCRegister NewReg = MAI.getNextIDRegister();
642 MAI.setRegisterAlias(MF, Reg, NewReg);
643 }
644 if (MI.getOpcode() != SPIRV::OpExtInst)
645 continue;
646 auto Set = MI.getOperand(2).getImm();
647 auto [It, Inserted] = MAI.ExtInstSetMap.try_emplace(Set);
648 if (Inserted)
649 It->second = MAI.getNextIDRegister();
650 }
651 }
652 }
653}
654
655// RequirementHandler implementations.
657 SPIRV::OperandCategory::OperandCategory Category, uint32_t i,
658 const SPIRVSubtarget &ST) {
659 addRequirements(getSymbolicOperandRequirements(Category, i, ST, *this));
660}
661
662void SPIRV::RequirementHandler::recursiveAddCapabilities(
663 const CapabilityList &ToPrune) {
664 for (const auto &Cap : ToPrune) {
665 AllCaps.insert(Cap);
666 CapabilityList ImplicitDecls =
667 getSymbolicOperandCapabilities(OperandCategory::CapabilityOperand, Cap);
668 recursiveAddCapabilities(ImplicitDecls);
669 }
670}
671
673 for (const auto &Cap : ToAdd) {
674 bool IsNewlyInserted = AllCaps.insert(Cap).second;
675 if (!IsNewlyInserted) // Don't re-add if it's already been declared.
676 continue;
677 CapabilityList ImplicitDecls =
678 getSymbolicOperandCapabilities(OperandCategory::CapabilityOperand, Cap);
679 recursiveAddCapabilities(ImplicitDecls);
680 MinimalCaps.push_back(Cap);
681 }
682}
683
685 const SPIRV::Requirements &Req) {
686 if (!Req.IsSatisfiable)
687 report_fatal_error("Adding SPIR-V requirements this target can't satisfy.");
688
689 if (Req.Cap.has_value())
690 addCapabilities({Req.Cap.value()});
691
692 addExtensions(Req.Exts);
693
694 if (!Req.MinVer.empty()) {
695 if (!MaxVersion.empty() && Req.MinVer > MaxVersion) {
696 LLVM_DEBUG(dbgs() << "Conflicting version requirements: >= " << Req.MinVer
697 << " and <= " << MaxVersion << "\n");
698 report_fatal_error("Adding SPIR-V requirements that can't be satisfied.");
699 }
700
701 if (MinVersion.empty() || Req.MinVer > MinVersion)
702 MinVersion = Req.MinVer;
703 }
704
705 if (!Req.MaxVer.empty()) {
706 if (!MinVersion.empty() && Req.MaxVer < MinVersion) {
707 LLVM_DEBUG(dbgs() << "Conflicting version requirements: <= " << Req.MaxVer
708 << " and >= " << MinVersion << "\n");
709 report_fatal_error("Adding SPIR-V requirements that can't be satisfied.");
710 }
711
712 if (MaxVersion.empty() || Req.MaxVer < MaxVersion)
713 MaxVersion = Req.MaxVer;
714 }
715}
716
718 const SPIRVSubtarget &ST) const {
719 // Report as many errors as possible before aborting the compilation.
720 bool IsSatisfiable = true;
721 auto TargetVer = ST.getSPIRVVersion();
722
723 if (!MaxVersion.empty() && !TargetVer.empty() && MaxVersion < TargetVer) {
725 dbgs() << "Target SPIR-V version too high for required features\n"
726 << "Required max version: " << MaxVersion << " target version "
727 << TargetVer << "\n");
728 IsSatisfiable = false;
729 }
730
731 if (!MinVersion.empty() && !TargetVer.empty() && MinVersion > TargetVer) {
732 LLVM_DEBUG(dbgs() << "Target SPIR-V version too low for required features\n"
733 << "Required min version: " << MinVersion
734 << " target version " << TargetVer << "\n");
735 IsSatisfiable = false;
736 }
737
738 if (!MinVersion.empty() && !MaxVersion.empty() && MinVersion > MaxVersion) {
740 dbgs()
741 << "Version is too low for some features and too high for others.\n"
742 << "Required SPIR-V min version: " << MinVersion
743 << " required SPIR-V max version " << MaxVersion << "\n");
744 IsSatisfiable = false;
745 }
746
747 AvoidCapabilitiesSet AvoidCaps;
748 if (!ST.isShader())
749 AvoidCaps.S.insert(SPIRV::Capability::Shader);
750 else
751 AvoidCaps.S.insert(SPIRV::Capability::Kernel);
752
753 for (auto Cap : MinimalCaps) {
754 if (AvailableCaps.contains(Cap) && !AvoidCaps.S.contains(Cap))
755 continue;
756 LLVM_DEBUG(dbgs() << "Capability not supported: "
758 OperandCategory::CapabilityOperand, Cap)
759 << "\n");
760 IsSatisfiable = false;
761 }
762
763 for (auto Ext : AllExtensions) {
764 if (ST.canUseExtension(Ext))
765 continue;
766 LLVM_DEBUG(dbgs() << "Extension not supported: "
768 OperandCategory::ExtensionOperand, Ext)
769 << "\n");
770 IsSatisfiable = false;
771 }
772
773 if (!IsSatisfiable)
774 report_fatal_error("Unable to meet SPIR-V requirements for this target.");
775}
776
777// Add the given capabilities and all their implicitly defined capabilities too.
779 for (const auto Cap : ToAdd)
780 if (AvailableCaps.insert(Cap).second)
781 addAvailableCaps(getSymbolicOperandCapabilities(
782 SPIRV::OperandCategory::CapabilityOperand, Cap));
783}
784
786 const Capability::Capability ToRemove,
787 const Capability::Capability IfPresent) {
788 if (AllCaps.contains(IfPresent))
789 AllCaps.erase(ToRemove);
790}
791
792namespace llvm {
793namespace SPIRV {
794void RequirementHandler::initAvailableCapabilities(const SPIRVSubtarget &ST) {
795 // Provided by both all supported Vulkan versions and OpenCl.
796 addAvailableCaps({Capability::Shader, Capability::Linkage, Capability::Int8,
797 Capability::Int16});
798
799 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 3)))
800 addAvailableCaps({Capability::GroupNonUniform,
801 Capability::GroupNonUniformVote,
802 Capability::GroupNonUniformArithmetic,
803 Capability::GroupNonUniformBallot,
804 Capability::GroupNonUniformClustered,
805 Capability::GroupNonUniformShuffle,
806 Capability::GroupNonUniformShuffleRelative});
807
808 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 6)))
809 addAvailableCaps({Capability::DotProduct, Capability::DotProductInputAll,
810 Capability::DotProductInput4x8Bit,
811 Capability::DotProductInput4x8BitPacked,
812 Capability::DemoteToHelperInvocation});
813
814 // Add capabilities enabled by extensions.
815 for (auto Extension : ST.getAllAvailableExtensions()) {
816 CapabilityList EnabledCapabilities =
818 addAvailableCaps(EnabledCapabilities);
819 }
820
821 if (!ST.isShader()) {
822 initAvailableCapabilitiesForOpenCL(ST);
823 return;
824 }
825
826 if (ST.isShader()) {
827 initAvailableCapabilitiesForVulkan(ST);
828 return;
829 }
830
831 report_fatal_error("Unimplemented environment for SPIR-V generation.");
832}
833
834void RequirementHandler::initAvailableCapabilitiesForOpenCL(
835 const SPIRVSubtarget &ST) {
836 // Add the min requirements for different OpenCL and SPIR-V versions.
837 addAvailableCaps({Capability::Addresses, Capability::Float16Buffer,
838 Capability::Kernel, Capability::Vector16,
839 Capability::Groups, Capability::GenericPointer,
840 Capability::StorageImageWriteWithoutFormat,
841 Capability::StorageImageReadWithoutFormat});
842 if (ST.hasOpenCLFullProfile())
843 addAvailableCaps({Capability::Int64, Capability::Int64Atomics});
844 if (ST.hasOpenCLImageSupport()) {
845 addAvailableCaps({Capability::ImageBasic, Capability::LiteralSampler,
846 Capability::Image1D, Capability::SampledBuffer,
847 Capability::ImageBuffer});
848 if (ST.isAtLeastOpenCLVer(VersionTuple(2, 0)))
849 addAvailableCaps({Capability::ImageReadWrite});
850 }
851 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 1)) &&
852 ST.isAtLeastOpenCLVer(VersionTuple(2, 2)))
853 addAvailableCaps({Capability::SubgroupDispatch, Capability::PipeStorage});
854 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 4)))
855 addAvailableCaps({Capability::DenormPreserve, Capability::DenormFlushToZero,
856 Capability::SignedZeroInfNanPreserve,
857 Capability::RoundingModeRTE,
858 Capability::RoundingModeRTZ});
859 // TODO: verify if this needs some checks.
860 addAvailableCaps({Capability::Float16, Capability::Float64});
861
862 // TODO: add OpenCL extensions.
863}
864
865void RequirementHandler::initAvailableCapabilitiesForVulkan(
866 const SPIRVSubtarget &ST) {
867
868 // Core in Vulkan 1.1 and earlier.
869 addAvailableCaps({Capability::Int64, Capability::Float16, Capability::Float64,
870 Capability::GroupNonUniform, Capability::Image1D,
871 Capability::SampledBuffer, Capability::ImageBuffer,
872 Capability::UniformBufferArrayDynamicIndexing,
873 Capability::SampledImageArrayDynamicIndexing,
874 Capability::StorageBufferArrayDynamicIndexing,
875 Capability::StorageImageArrayDynamicIndexing});
876
877 // Became core in Vulkan 1.2
878 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 5))) {
880 {Capability::ShaderNonUniformEXT, Capability::RuntimeDescriptorArrayEXT,
881 Capability::InputAttachmentArrayDynamicIndexingEXT,
882 Capability::UniformTexelBufferArrayDynamicIndexingEXT,
883 Capability::StorageTexelBufferArrayDynamicIndexingEXT,
884 Capability::UniformBufferArrayNonUniformIndexingEXT,
885 Capability::SampledImageArrayNonUniformIndexingEXT,
886 Capability::StorageBufferArrayNonUniformIndexingEXT,
887 Capability::StorageImageArrayNonUniformIndexingEXT,
888 Capability::InputAttachmentArrayNonUniformIndexingEXT,
889 Capability::UniformTexelBufferArrayNonUniformIndexingEXT,
890 Capability::StorageTexelBufferArrayNonUniformIndexingEXT});
891 }
892
893 // Became core in Vulkan 1.3
894 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 6)))
895 addAvailableCaps({Capability::StorageImageWriteWithoutFormat,
896 Capability::StorageImageReadWithoutFormat});
897}
898
899} // namespace SPIRV
900} // namespace llvm
901
902// Add the required capabilities from a decoration instruction (including
903// BuiltIns).
904static void addOpDecorateReqs(const MachineInstr &MI, unsigned DecIndex,
906 const SPIRVSubtarget &ST) {
907 int64_t DecOp = MI.getOperand(DecIndex).getImm();
908 auto Dec = static_cast<SPIRV::Decoration::Decoration>(DecOp);
909 Reqs.addRequirements(getSymbolicOperandRequirements(
910 SPIRV::OperandCategory::DecorationOperand, Dec, ST, Reqs));
911
912 if (Dec == SPIRV::Decoration::BuiltIn) {
913 int64_t BuiltInOp = MI.getOperand(DecIndex + 1).getImm();
914 auto BuiltIn = static_cast<SPIRV::BuiltIn::BuiltIn>(BuiltInOp);
915 Reqs.addRequirements(getSymbolicOperandRequirements(
916 SPIRV::OperandCategory::BuiltInOperand, BuiltIn, ST, Reqs));
917 } else if (Dec == SPIRV::Decoration::LinkageAttributes) {
918 int64_t LinkageOp = MI.getOperand(MI.getNumOperands() - 1).getImm();
919 SPIRV::LinkageType::LinkageType LnkType =
920 static_cast<SPIRV::LinkageType::LinkageType>(LinkageOp);
921 if (LnkType == SPIRV::LinkageType::LinkOnceODR)
922 Reqs.addExtension(SPIRV::Extension::SPV_KHR_linkonce_odr);
923 } else if (Dec == SPIRV::Decoration::CacheControlLoadINTEL ||
924 Dec == SPIRV::Decoration::CacheControlStoreINTEL) {
925 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_cache_controls);
926 } else if (Dec == SPIRV::Decoration::HostAccessINTEL) {
927 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_global_variable_host_access);
928 } else if (Dec == SPIRV::Decoration::InitModeINTEL ||
929 Dec == SPIRV::Decoration::ImplementInRegisterMapINTEL) {
930 Reqs.addExtension(
931 SPIRV::Extension::SPV_INTEL_global_variable_fpga_decorations);
932 } else if (Dec == SPIRV::Decoration::NonUniformEXT) {
933 Reqs.addRequirements(SPIRV::Capability::ShaderNonUniformEXT);
934 } else if (Dec == SPIRV::Decoration::FPMaxErrorDecorationINTEL) {
935 Reqs.addRequirements(SPIRV::Capability::FPMaxErrorINTEL);
936 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_fp_max_error);
937 }
938}
939
940// Add requirements for image handling.
941static void addOpTypeImageReqs(const MachineInstr &MI,
943 const SPIRVSubtarget &ST) {
944 assert(MI.getNumOperands() >= 8 && "Insufficient operands for OpTypeImage");
945 // The operand indices used here are based on the OpTypeImage layout, which
946 // the MachineInstr follows as well.
947 int64_t ImgFormatOp = MI.getOperand(7).getImm();
948 auto ImgFormat = static_cast<SPIRV::ImageFormat::ImageFormat>(ImgFormatOp);
949 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ImageFormatOperand,
950 ImgFormat, ST);
951
952 bool IsArrayed = MI.getOperand(4).getImm() == 1;
953 bool IsMultisampled = MI.getOperand(5).getImm() == 1;
954 bool NoSampler = MI.getOperand(6).getImm() == 2;
955 // Add dimension requirements.
956 assert(MI.getOperand(2).isImm());
957 switch (MI.getOperand(2).getImm()) {
958 case SPIRV::Dim::DIM_1D:
959 Reqs.addRequirements(NoSampler ? SPIRV::Capability::Image1D
960 : SPIRV::Capability::Sampled1D);
961 break;
962 case SPIRV::Dim::DIM_2D:
963 if (IsMultisampled && NoSampler)
964 Reqs.addRequirements(SPIRV::Capability::ImageMSArray);
965 break;
966 case SPIRV::Dim::DIM_Cube:
967 Reqs.addRequirements(SPIRV::Capability::Shader);
968 if (IsArrayed)
969 Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageCubeArray
970 : SPIRV::Capability::SampledCubeArray);
971 break;
972 case SPIRV::Dim::DIM_Rect:
973 Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageRect
974 : SPIRV::Capability::SampledRect);
975 break;
976 case SPIRV::Dim::DIM_Buffer:
977 Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageBuffer
978 : SPIRV::Capability::SampledBuffer);
979 break;
980 case SPIRV::Dim::DIM_SubpassData:
981 Reqs.addRequirements(SPIRV::Capability::InputAttachment);
982 break;
983 }
984
985 // Has optional access qualifier.
986 if (!ST.isShader()) {
987 if (MI.getNumOperands() > 8 &&
988 MI.getOperand(8).getImm() == SPIRV::AccessQualifier::ReadWrite)
989 Reqs.addRequirements(SPIRV::Capability::ImageReadWrite);
990 else
991 Reqs.addRequirements(SPIRV::Capability::ImageBasic);
992 }
993}
994
995// Add requirements for handling atomic float instructions
996#define ATOM_FLT_REQ_EXT_MSG(ExtName) \
997 "The atomic float instruction requires the following SPIR-V " \
998 "extension: SPV_EXT_shader_atomic_float" ExtName
999static void AddAtomicFloatRequirements(const MachineInstr &MI,
1001 const SPIRVSubtarget &ST) {
1002 assert(MI.getOperand(1).isReg() &&
1003 "Expect register operand in atomic float instruction");
1004 Register TypeReg = MI.getOperand(1).getReg();
1005 SPIRVType *TypeDef = MI.getMF()->getRegInfo().getVRegDef(TypeReg);
1006 if (TypeDef->getOpcode() != SPIRV::OpTypeFloat)
1007 report_fatal_error("Result type of an atomic float instruction must be a "
1008 "floating-point type scalar");
1009
1010 unsigned BitWidth = TypeDef->getOperand(1).getImm();
1011 unsigned Op = MI.getOpcode();
1012 if (Op == SPIRV::OpAtomicFAddEXT) {
1013 if (!ST.canUseExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_add))
1015 Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_add);
1016 switch (BitWidth) {
1017 case 16:
1018 if (!ST.canUseExtension(
1019 SPIRV::Extension::SPV_EXT_shader_atomic_float16_add))
1020 report_fatal_error(ATOM_FLT_REQ_EXT_MSG("16_add"), false);
1021 Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float16_add);
1022 Reqs.addCapability(SPIRV::Capability::AtomicFloat16AddEXT);
1023 break;
1024 case 32:
1025 Reqs.addCapability(SPIRV::Capability::AtomicFloat32AddEXT);
1026 break;
1027 case 64:
1028 Reqs.addCapability(SPIRV::Capability::AtomicFloat64AddEXT);
1029 break;
1030 default:
1032 "Unexpected floating-point type width in atomic float instruction");
1033 }
1034 } else {
1035 if (!ST.canUseExtension(
1036 SPIRV::Extension::SPV_EXT_shader_atomic_float_min_max))
1037 report_fatal_error(ATOM_FLT_REQ_EXT_MSG("_min_max"), false);
1038 Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_min_max);
1039 switch (BitWidth) {
1040 case 16:
1041 Reqs.addCapability(SPIRV::Capability::AtomicFloat16MinMaxEXT);
1042 break;
1043 case 32:
1044 Reqs.addCapability(SPIRV::Capability::AtomicFloat32MinMaxEXT);
1045 break;
1046 case 64:
1047 Reqs.addCapability(SPIRV::Capability::AtomicFloat64MinMaxEXT);
1048 break;
1049 default:
1051 "Unexpected floating-point type width in atomic float instruction");
1052 }
1053 }
1054}
1055
1056bool isUniformTexelBuffer(MachineInstr *ImageInst) {
1057 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1058 return false;
1059 uint32_t Dim = ImageInst->getOperand(2).getImm();
1060 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1061 return Dim == SPIRV::Dim::DIM_Buffer && Sampled == 1;
1062}
1063
1064bool isStorageTexelBuffer(MachineInstr *ImageInst) {
1065 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1066 return false;
1067 uint32_t Dim = ImageInst->getOperand(2).getImm();
1068 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1069 return Dim == SPIRV::Dim::DIM_Buffer && Sampled == 2;
1070}
1071
1072bool isSampledImage(MachineInstr *ImageInst) {
1073 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1074 return false;
1075 uint32_t Dim = ImageInst->getOperand(2).getImm();
1076 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1077 return Dim != SPIRV::Dim::DIM_Buffer && Sampled == 1;
1078}
1079
1080bool isInputAttachment(MachineInstr *ImageInst) {
1081 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1082 return false;
1083 uint32_t Dim = ImageInst->getOperand(2).getImm();
1084 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1085 return Dim == SPIRV::Dim::DIM_SubpassData && Sampled == 2;
1086}
1087
1088bool isStorageImage(MachineInstr *ImageInst) {
1089 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1090 return false;
1091 uint32_t Dim = ImageInst->getOperand(2).getImm();
1092 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1093 return Dim != SPIRV::Dim::DIM_Buffer && Sampled == 2;
1094}
1095
1096bool isCombinedImageSampler(MachineInstr *SampledImageInst) {
1097 if (SampledImageInst->getOpcode() != SPIRV::OpTypeSampledImage)
1098 return false;
1099
1100 const MachineRegisterInfo &MRI = SampledImageInst->getMF()->getRegInfo();
1101 Register ImageReg = SampledImageInst->getOperand(1).getReg();
1102 auto *ImageInst = MRI.getUniqueVRegDef(ImageReg);
1103 return isSampledImage(ImageInst);
1104}
1105
1106bool hasNonUniformDecoration(Register Reg, const MachineRegisterInfo &MRI) {
1107 for (const auto &MI : MRI.reg_instructions(Reg)) {
1108 if (MI.getOpcode() != SPIRV::OpDecorate)
1109 continue;
1110
1111 uint32_t Dec = MI.getOperand(1).getImm();
1112 if (Dec == SPIRV::Decoration::NonUniformEXT)
1113 return true;
1114 }
1115 return false;
1116}
1117
1118void addOpAccessChainReqs(const MachineInstr &Instr,
1120 const SPIRVSubtarget &Subtarget) {
1121 const MachineRegisterInfo &MRI = Instr.getMF()->getRegInfo();
1122 // Get the result type. If it is an image type, then the shader uses
1123 // descriptor indexing. The appropriate capabilities will be added based
1124 // on the specifics of the image.
1125 Register ResTypeReg = Instr.getOperand(1).getReg();
1126 MachineInstr *ResTypeInst = MRI.getUniqueVRegDef(ResTypeReg);
1127
1128 assert(ResTypeInst->getOpcode() == SPIRV::OpTypePointer);
1129 uint32_t StorageClass = ResTypeInst->getOperand(1).getImm();
1130 if (StorageClass != SPIRV::StorageClass::StorageClass::UniformConstant &&
1131 StorageClass != SPIRV::StorageClass::StorageClass::Uniform &&
1132 StorageClass != SPIRV::StorageClass::StorageClass::StorageBuffer) {
1133 return;
1134 }
1135
1136 Register PointeeTypeReg = ResTypeInst->getOperand(2).getReg();
1137 MachineInstr *PointeeType = MRI.getUniqueVRegDef(PointeeTypeReg);
1138 if (PointeeType->getOpcode() != SPIRV::OpTypeImage &&
1139 PointeeType->getOpcode() != SPIRV::OpTypeSampledImage &&
1140 PointeeType->getOpcode() != SPIRV::OpTypeSampler) {
1141 return;
1142 }
1143
1144 bool IsNonUniform =
1145 hasNonUniformDecoration(Instr.getOperand(0).getReg(), MRI);
1146 if (isUniformTexelBuffer(PointeeType)) {
1147 if (IsNonUniform)
1148 Handler.addRequirements(
1149 SPIRV::Capability::UniformTexelBufferArrayNonUniformIndexingEXT);
1150 else
1151 Handler.addRequirements(
1152 SPIRV::Capability::UniformTexelBufferArrayDynamicIndexingEXT);
1153 } else if (isInputAttachment(PointeeType)) {
1154 if (IsNonUniform)
1155 Handler.addRequirements(
1156 SPIRV::Capability::InputAttachmentArrayNonUniformIndexingEXT);
1157 else
1158 Handler.addRequirements(
1159 SPIRV::Capability::InputAttachmentArrayDynamicIndexingEXT);
1160 } else if (isStorageTexelBuffer(PointeeType)) {
1161 if (IsNonUniform)
1162 Handler.addRequirements(
1163 SPIRV::Capability::StorageTexelBufferArrayNonUniformIndexingEXT);
1164 else
1165 Handler.addRequirements(
1166 SPIRV::Capability::StorageTexelBufferArrayDynamicIndexingEXT);
1167 } else if (isSampledImage(PointeeType) ||
1168 isCombinedImageSampler(PointeeType) ||
1169 PointeeType->getOpcode() == SPIRV::OpTypeSampler) {
1170 if (IsNonUniform)
1171 Handler.addRequirements(
1172 SPIRV::Capability::SampledImageArrayNonUniformIndexingEXT);
1173 else
1174 Handler.addRequirements(
1175 SPIRV::Capability::SampledImageArrayDynamicIndexing);
1176 } else if (isStorageImage(PointeeType)) {
1177 if (IsNonUniform)
1178 Handler.addRequirements(
1179 SPIRV::Capability::StorageImageArrayNonUniformIndexingEXT);
1180 else
1181 Handler.addRequirements(
1182 SPIRV::Capability::StorageImageArrayDynamicIndexing);
1183 }
1184}
1185
1186static bool isImageTypeWithUnknownFormat(SPIRVType *TypeInst) {
1187 if (TypeInst->getOpcode() != SPIRV::OpTypeImage)
1188 return false;
1189 assert(TypeInst->getOperand(7).isImm() && "The image format must be an imm.");
1190 return TypeInst->getOperand(7).getImm() == 0;
1191}
1192
1193static void AddDotProductRequirements(const MachineInstr &MI,
1195 const SPIRVSubtarget &ST) {
1196 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product))
1197 Reqs.addExtension(SPIRV::Extension::SPV_KHR_integer_dot_product);
1198 Reqs.addCapability(SPIRV::Capability::DotProduct);
1199
1200 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1201 assert(MI.getOperand(2).isReg() && "Unexpected operand in dot");
1202 // We do not consider what the previous instruction is. This is just used
1203 // to get the input register and to check the type.
1204 const MachineInstr *Input = MRI.getVRegDef(MI.getOperand(2).getReg());
1205 assert(Input->getOperand(1).isReg() && "Unexpected operand in dot input");
1206 Register InputReg = Input->getOperand(1).getReg();
1207
1208 SPIRVType *TypeDef = MRI.getVRegDef(InputReg);
1209 if (TypeDef->getOpcode() == SPIRV::OpTypeInt) {
1210 assert(TypeDef->getOperand(1).getImm() == 32);
1211 Reqs.addCapability(SPIRV::Capability::DotProductInput4x8BitPacked);
1212 } else if (TypeDef->getOpcode() == SPIRV::OpTypeVector) {
1213 SPIRVType *ScalarTypeDef = MRI.getVRegDef(TypeDef->getOperand(1).getReg());
1214 assert(ScalarTypeDef->getOpcode() == SPIRV::OpTypeInt);
1215 if (ScalarTypeDef->getOperand(1).getImm() == 8) {
1216 assert(TypeDef->getOperand(2).getImm() == 4 &&
1217 "Dot operand of 8-bit integer type requires 4 components");
1218 Reqs.addCapability(SPIRV::Capability::DotProductInput4x8Bit);
1219 } else {
1220 Reqs.addCapability(SPIRV::Capability::DotProductInputAll);
1221 }
1222 }
1223}
1224
1225void addInstrRequirements(const MachineInstr &MI,
1227 const SPIRVSubtarget &ST) {
1228 switch (MI.getOpcode()) {
1229 case SPIRV::OpMemoryModel: {
1230 int64_t Addr = MI.getOperand(0).getImm();
1231 Reqs.getAndAddRequirements(SPIRV::OperandCategory::AddressingModelOperand,
1232 Addr, ST);
1233 int64_t Mem = MI.getOperand(1).getImm();
1234 Reqs.getAndAddRequirements(SPIRV::OperandCategory::MemoryModelOperand, Mem,
1235 ST);
1236 break;
1237 }
1238 case SPIRV::OpEntryPoint: {
1239 int64_t Exe = MI.getOperand(0).getImm();
1240 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ExecutionModelOperand,
1241 Exe, ST);
1242 break;
1243 }
1244 case SPIRV::OpExecutionMode:
1245 case SPIRV::OpExecutionModeId: {
1246 int64_t Exe = MI.getOperand(1).getImm();
1247 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ExecutionModeOperand,
1248 Exe, ST);
1249 break;
1250 }
1251 case SPIRV::OpTypeMatrix:
1252 Reqs.addCapability(SPIRV::Capability::Matrix);
1253 break;
1254 case SPIRV::OpTypeInt: {
1255 unsigned BitWidth = MI.getOperand(1).getImm();
1256 if (BitWidth == 64)
1257 Reqs.addCapability(SPIRV::Capability::Int64);
1258 else if (BitWidth == 16)
1259 Reqs.addCapability(SPIRV::Capability::Int16);
1260 else if (BitWidth == 8)
1261 Reqs.addCapability(SPIRV::Capability::Int8);
1262 break;
1263 }
1264 case SPIRV::OpTypeFloat: {
1265 unsigned BitWidth = MI.getOperand(1).getImm();
1266 if (BitWidth == 64)
1267 Reqs.addCapability(SPIRV::Capability::Float64);
1268 else if (BitWidth == 16)
1269 Reqs.addCapability(SPIRV::Capability::Float16);
1270 break;
1271 }
1272 case SPIRV::OpTypeVector: {
1273 unsigned NumComponents = MI.getOperand(2).getImm();
1274 if (NumComponents == 8 || NumComponents == 16)
1275 Reqs.addCapability(SPIRV::Capability::Vector16);
1276 break;
1277 }
1278 case SPIRV::OpTypePointer: {
1279 auto SC = MI.getOperand(1).getImm();
1280 Reqs.getAndAddRequirements(SPIRV::OperandCategory::StorageClassOperand, SC,
1281 ST);
1282 // If it's a type of pointer to float16 targeting OpenCL, add Float16Buffer
1283 // capability.
1284 if (ST.isShader())
1285 break;
1286 assert(MI.getOperand(2).isReg());
1287 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1288 SPIRVType *TypeDef = MRI.getVRegDef(MI.getOperand(2).getReg());
1289 if (TypeDef->getOpcode() == SPIRV::OpTypeFloat &&
1290 TypeDef->getOperand(1).getImm() == 16)
1291 Reqs.addCapability(SPIRV::Capability::Float16Buffer);
1292 break;
1293 }
1294 case SPIRV::OpExtInst: {
1295 if (MI.getOperand(2).getImm() ==
1296 static_cast<int64_t>(
1297 SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100)) {
1298 Reqs.addExtension(SPIRV::Extension::SPV_KHR_non_semantic_info);
1299 }
1300 break;
1301 }
1302 case SPIRV::OpAliasDomainDeclINTEL:
1303 case SPIRV::OpAliasScopeDeclINTEL:
1304 case SPIRV::OpAliasScopeListDeclINTEL: {
1305 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing);
1306 Reqs.addCapability(SPIRV::Capability::MemoryAccessAliasingINTEL);
1307 break;
1308 }
1309 case SPIRV::OpBitReverse:
1310 case SPIRV::OpBitFieldInsert:
1311 case SPIRV::OpBitFieldSExtract:
1312 case SPIRV::OpBitFieldUExtract:
1313 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions)) {
1314 Reqs.addCapability(SPIRV::Capability::Shader);
1315 break;
1316 }
1317 Reqs.addExtension(SPIRV::Extension::SPV_KHR_bit_instructions);
1318 Reqs.addCapability(SPIRV::Capability::BitInstructions);
1319 break;
1320 case SPIRV::OpTypeRuntimeArray:
1321 Reqs.addCapability(SPIRV::Capability::Shader);
1322 break;
1323 case SPIRV::OpTypeOpaque:
1324 case SPIRV::OpTypeEvent:
1325 Reqs.addCapability(SPIRV::Capability::Kernel);
1326 break;
1327 case SPIRV::OpTypePipe:
1328 case SPIRV::OpTypeReserveId:
1329 Reqs.addCapability(SPIRV::Capability::Pipes);
1330 break;
1331 case SPIRV::OpTypeDeviceEvent:
1332 case SPIRV::OpTypeQueue:
1333 case SPIRV::OpBuildNDRange:
1334 Reqs.addCapability(SPIRV::Capability::DeviceEnqueue);
1335 break;
1336 case SPIRV::OpDecorate:
1337 case SPIRV::OpDecorateId:
1338 case SPIRV::OpDecorateString:
1339 addOpDecorateReqs(MI, 1, Reqs, ST);
1340 break;
1341 case SPIRV::OpMemberDecorate:
1342 case SPIRV::OpMemberDecorateString:
1343 addOpDecorateReqs(MI, 2, Reqs, ST);
1344 break;
1345 case SPIRV::OpInBoundsPtrAccessChain:
1346 Reqs.addCapability(SPIRV::Capability::Addresses);
1347 break;
1348 case SPIRV::OpConstantSampler:
1349 Reqs.addCapability(SPIRV::Capability::LiteralSampler);
1350 break;
1351 case SPIRV::OpInBoundsAccessChain:
1352 case SPIRV::OpAccessChain:
1353 addOpAccessChainReqs(MI, Reqs, ST);
1354 break;
1355 case SPIRV::OpTypeImage:
1356 addOpTypeImageReqs(MI, Reqs, ST);
1357 break;
1358 case SPIRV::OpTypeSampler:
1359 if (!ST.isShader()) {
1360 Reqs.addCapability(SPIRV::Capability::ImageBasic);
1361 }
1362 break;
1363 case SPIRV::OpTypeForwardPointer:
1364 // TODO: check if it's OpenCL's kernel.
1365 Reqs.addCapability(SPIRV::Capability::Addresses);
1366 break;
1367 case SPIRV::OpAtomicFlagTestAndSet:
1368 case SPIRV::OpAtomicLoad:
1369 case SPIRV::OpAtomicStore:
1370 case SPIRV::OpAtomicExchange:
1371 case SPIRV::OpAtomicCompareExchange:
1372 case SPIRV::OpAtomicIIncrement:
1373 case SPIRV::OpAtomicIDecrement:
1374 case SPIRV::OpAtomicIAdd:
1375 case SPIRV::OpAtomicISub:
1376 case SPIRV::OpAtomicUMin:
1377 case SPIRV::OpAtomicUMax:
1378 case SPIRV::OpAtomicSMin:
1379 case SPIRV::OpAtomicSMax:
1380 case SPIRV::OpAtomicAnd:
1381 case SPIRV::OpAtomicOr:
1382 case SPIRV::OpAtomicXor: {
1383 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1384 const MachineInstr *InstrPtr = &MI;
1385 if (MI.getOpcode() == SPIRV::OpAtomicStore) {
1386 assert(MI.getOperand(3).isReg());
1387 InstrPtr = MRI.getVRegDef(MI.getOperand(3).getReg());
1388 assert(InstrPtr && "Unexpected type instruction for OpAtomicStore");
1389 }
1390 assert(InstrPtr->getOperand(1).isReg() && "Unexpected operand in atomic");
1391 Register TypeReg = InstrPtr->getOperand(1).getReg();
1392 SPIRVType *TypeDef = MRI.getVRegDef(TypeReg);
1393 if (TypeDef->getOpcode() == SPIRV::OpTypeInt) {
1394 unsigned BitWidth = TypeDef->getOperand(1).getImm();
1395 if (BitWidth == 64)
1396 Reqs.addCapability(SPIRV::Capability::Int64Atomics);
1397 }
1398 break;
1399 }
1400 case SPIRV::OpGroupNonUniformIAdd:
1401 case SPIRV::OpGroupNonUniformFAdd:
1402 case SPIRV::OpGroupNonUniformIMul:
1403 case SPIRV::OpGroupNonUniformFMul:
1404 case SPIRV::OpGroupNonUniformSMin:
1405 case SPIRV::OpGroupNonUniformUMin:
1406 case SPIRV::OpGroupNonUniformFMin:
1407 case SPIRV::OpGroupNonUniformSMax:
1408 case SPIRV::OpGroupNonUniformUMax:
1409 case SPIRV::OpGroupNonUniformFMax:
1410 case SPIRV::OpGroupNonUniformBitwiseAnd:
1411 case SPIRV::OpGroupNonUniformBitwiseOr:
1412 case SPIRV::OpGroupNonUniformBitwiseXor:
1413 case SPIRV::OpGroupNonUniformLogicalAnd:
1414 case SPIRV::OpGroupNonUniformLogicalOr:
1415 case SPIRV::OpGroupNonUniformLogicalXor: {
1416 assert(MI.getOperand(3).isImm());
1417 int64_t GroupOp = MI.getOperand(3).getImm();
1418 switch (GroupOp) {
1419 case SPIRV::GroupOperation::Reduce:
1420 case SPIRV::GroupOperation::InclusiveScan:
1421 case SPIRV::GroupOperation::ExclusiveScan:
1422 Reqs.addCapability(SPIRV::Capability::GroupNonUniformArithmetic);
1423 break;
1424 case SPIRV::GroupOperation::ClusteredReduce:
1425 Reqs.addCapability(SPIRV::Capability::GroupNonUniformClustered);
1426 break;
1427 case SPIRV::GroupOperation::PartitionedReduceNV:
1428 case SPIRV::GroupOperation::PartitionedInclusiveScanNV:
1429 case SPIRV::GroupOperation::PartitionedExclusiveScanNV:
1430 Reqs.addCapability(SPIRV::Capability::GroupNonUniformPartitionedNV);
1431 break;
1432 }
1433 break;
1434 }
1435 case SPIRV::OpGroupNonUniformShuffle:
1436 case SPIRV::OpGroupNonUniformShuffleXor:
1437 Reqs.addCapability(SPIRV::Capability::GroupNonUniformShuffle);
1438 break;
1439 case SPIRV::OpGroupNonUniformShuffleUp:
1440 case SPIRV::OpGroupNonUniformShuffleDown:
1441 Reqs.addCapability(SPIRV::Capability::GroupNonUniformShuffleRelative);
1442 break;
1443 case SPIRV::OpGroupAll:
1444 case SPIRV::OpGroupAny:
1445 case SPIRV::OpGroupBroadcast:
1446 case SPIRV::OpGroupIAdd:
1447 case SPIRV::OpGroupFAdd:
1448 case SPIRV::OpGroupFMin:
1449 case SPIRV::OpGroupUMin:
1450 case SPIRV::OpGroupSMin:
1451 case SPIRV::OpGroupFMax:
1452 case SPIRV::OpGroupUMax:
1453 case SPIRV::OpGroupSMax:
1454 Reqs.addCapability(SPIRV::Capability::Groups);
1455 break;
1456 case SPIRV::OpGroupNonUniformElect:
1457 Reqs.addCapability(SPIRV::Capability::GroupNonUniform);
1458 break;
1459 case SPIRV::OpGroupNonUniformAll:
1460 case SPIRV::OpGroupNonUniformAny:
1461 case SPIRV::OpGroupNonUniformAllEqual:
1462 Reqs.addCapability(SPIRV::Capability::GroupNonUniformVote);
1463 break;
1464 case SPIRV::OpGroupNonUniformBroadcast:
1465 case SPIRV::OpGroupNonUniformBroadcastFirst:
1466 case SPIRV::OpGroupNonUniformBallot:
1467 case SPIRV::OpGroupNonUniformInverseBallot:
1468 case SPIRV::OpGroupNonUniformBallotBitExtract:
1469 case SPIRV::OpGroupNonUniformBallotBitCount:
1470 case SPIRV::OpGroupNonUniformBallotFindLSB:
1471 case SPIRV::OpGroupNonUniformBallotFindMSB:
1472 Reqs.addCapability(SPIRV::Capability::GroupNonUniformBallot);
1473 break;
1474 case SPIRV::OpSubgroupShuffleINTEL:
1475 case SPIRV::OpSubgroupShuffleDownINTEL:
1476 case SPIRV::OpSubgroupShuffleUpINTEL:
1477 case SPIRV::OpSubgroupShuffleXorINTEL:
1478 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
1479 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
1480 Reqs.addCapability(SPIRV::Capability::SubgroupShuffleINTEL);
1481 }
1482 break;
1483 case SPIRV::OpSubgroupBlockReadINTEL:
1484 case SPIRV::OpSubgroupBlockWriteINTEL:
1485 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
1486 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
1487 Reqs.addCapability(SPIRV::Capability::SubgroupBufferBlockIOINTEL);
1488 }
1489 break;
1490 case SPIRV::OpSubgroupImageBlockReadINTEL:
1491 case SPIRV::OpSubgroupImageBlockWriteINTEL:
1492 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
1493 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
1494 Reqs.addCapability(SPIRV::Capability::SubgroupImageBlockIOINTEL);
1495 }
1496 break;
1497 case SPIRV::OpSubgroupImageMediaBlockReadINTEL:
1498 case SPIRV::OpSubgroupImageMediaBlockWriteINTEL:
1499 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_media_block_io)) {
1500 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_media_block_io);
1501 Reqs.addCapability(SPIRV::Capability::SubgroupImageMediaBlockIOINTEL);
1502 }
1503 break;
1504 case SPIRV::OpAssumeTrueKHR:
1505 case SPIRV::OpExpectKHR:
1506 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) {
1507 Reqs.addExtension(SPIRV::Extension::SPV_KHR_expect_assume);
1508 Reqs.addCapability(SPIRV::Capability::ExpectAssumeKHR);
1509 }
1510 break;
1511 case SPIRV::OpPtrCastToCrossWorkgroupINTEL:
1512 case SPIRV::OpCrossWorkgroupCastToPtrINTEL:
1513 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes)) {
1514 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes);
1515 Reqs.addCapability(SPIRV::Capability::USMStorageClassesINTEL);
1516 }
1517 break;
1518 case SPIRV::OpConstantFunctionPointerINTEL:
1519 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)) {
1520 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
1521 Reqs.addCapability(SPIRV::Capability::FunctionPointersINTEL);
1522 }
1523 break;
1524 case SPIRV::OpGroupNonUniformRotateKHR:
1525 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_subgroup_rotate))
1526 report_fatal_error("OpGroupNonUniformRotateKHR instruction requires the "
1527 "following SPIR-V extension: SPV_KHR_subgroup_rotate",
1528 false);
1529 Reqs.addExtension(SPIRV::Extension::SPV_KHR_subgroup_rotate);
1530 Reqs.addCapability(SPIRV::Capability::GroupNonUniformRotateKHR);
1531 Reqs.addCapability(SPIRV::Capability::GroupNonUniform);
1532 break;
1533 case SPIRV::OpGroupIMulKHR:
1534 case SPIRV::OpGroupFMulKHR:
1535 case SPIRV::OpGroupBitwiseAndKHR:
1536 case SPIRV::OpGroupBitwiseOrKHR:
1537 case SPIRV::OpGroupBitwiseXorKHR:
1538 case SPIRV::OpGroupLogicalAndKHR:
1539 case SPIRV::OpGroupLogicalOrKHR:
1540 case SPIRV::OpGroupLogicalXorKHR:
1541 if (ST.canUseExtension(
1542 SPIRV::Extension::SPV_KHR_uniform_group_instructions)) {
1543 Reqs.addExtension(SPIRV::Extension::SPV_KHR_uniform_group_instructions);
1544 Reqs.addCapability(SPIRV::Capability::GroupUniformArithmeticKHR);
1545 }
1546 break;
1547 case SPIRV::OpReadClockKHR:
1548 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_shader_clock))
1549 report_fatal_error("OpReadClockKHR instruction requires the "
1550 "following SPIR-V extension: SPV_KHR_shader_clock",
1551 false);
1552 Reqs.addExtension(SPIRV::Extension::SPV_KHR_shader_clock);
1553 Reqs.addCapability(SPIRV::Capability::ShaderClockKHR);
1554 break;
1555 case SPIRV::OpFunctionPointerCallINTEL:
1556 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)) {
1557 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
1558 Reqs.addCapability(SPIRV::Capability::FunctionPointersINTEL);
1559 }
1560 break;
1561 case SPIRV::OpAtomicFAddEXT:
1562 case SPIRV::OpAtomicFMinEXT:
1563 case SPIRV::OpAtomicFMaxEXT:
1564 AddAtomicFloatRequirements(MI, Reqs, ST);
1565 break;
1566 case SPIRV::OpConvertBF16ToFINTEL:
1567 case SPIRV::OpConvertFToBF16INTEL:
1568 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bfloat16_conversion)) {
1569 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_conversion);
1570 Reqs.addCapability(SPIRV::Capability::BFloat16ConversionINTEL);
1571 }
1572 break;
1573 case SPIRV::OpRoundFToTF32INTEL:
1574 if (ST.canUseExtension(
1575 SPIRV::Extension::SPV_INTEL_tensor_float32_conversion)) {
1576 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_tensor_float32_conversion);
1577 Reqs.addCapability(SPIRV::Capability::TensorFloat32RoundingINTEL);
1578 }
1579 break;
1580 case SPIRV::OpVariableLengthArrayINTEL:
1581 case SPIRV::OpSaveMemoryINTEL:
1582 case SPIRV::OpRestoreMemoryINTEL:
1583 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array)) {
1584 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_variable_length_array);
1585 Reqs.addCapability(SPIRV::Capability::VariableLengthArrayINTEL);
1586 }
1587 break;
1588 case SPIRV::OpAsmTargetINTEL:
1589 case SPIRV::OpAsmINTEL:
1590 case SPIRV::OpAsmCallINTEL:
1591 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_inline_assembly)) {
1592 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_inline_assembly);
1593 Reqs.addCapability(SPIRV::Capability::AsmINTEL);
1594 }
1595 break;
1596 case SPIRV::OpTypeCooperativeMatrixKHR:
1597 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix))
1599 "OpTypeCooperativeMatrixKHR type requires the "
1600 "following SPIR-V extension: SPV_KHR_cooperative_matrix",
1601 false);
1602 Reqs.addExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix);
1603 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixKHR);
1604 break;
1605 case SPIRV::OpArithmeticFenceEXT:
1606 if (!ST.canUseExtension(SPIRV::Extension::SPV_EXT_arithmetic_fence))
1607 report_fatal_error("OpArithmeticFenceEXT requires the "
1608 "following SPIR-V extension: SPV_EXT_arithmetic_fence",
1609 false);
1610 Reqs.addExtension(SPIRV::Extension::SPV_EXT_arithmetic_fence);
1611 Reqs.addCapability(SPIRV::Capability::ArithmeticFenceEXT);
1612 break;
1613 case SPIRV::OpControlBarrierArriveINTEL:
1614 case SPIRV::OpControlBarrierWaitINTEL:
1615 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_split_barrier)) {
1616 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_split_barrier);
1617 Reqs.addCapability(SPIRV::Capability::SplitBarrierINTEL);
1618 }
1619 break;
1620 case SPIRV::OpCooperativeMatrixMulAddKHR: {
1621 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix))
1622 report_fatal_error("Cooperative matrix instructions require the "
1623 "following SPIR-V extension: "
1624 "SPV_KHR_cooperative_matrix",
1625 false);
1626 Reqs.addExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix);
1627 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixKHR);
1628 constexpr unsigned MulAddMaxSize = 6;
1629 if (MI.getNumOperands() != MulAddMaxSize)
1630 break;
1631 const int64_t CoopOperands = MI.getOperand(MulAddMaxSize - 1).getImm();
1632 if (CoopOperands &
1633 SPIRV::CooperativeMatrixOperands::MatrixAAndBTF32ComponentsINTEL) {
1634 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
1635 report_fatal_error("MatrixAAndBTF32ComponentsINTEL type interpretation "
1636 "require the following SPIR-V extension: "
1637 "SPV_INTEL_joint_matrix",
1638 false);
1639 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
1640 Reqs.addCapability(
1641 SPIRV::Capability::CooperativeMatrixTF32ComponentTypeINTEL);
1642 }
1643 if (CoopOperands & SPIRV::CooperativeMatrixOperands::
1644 MatrixAAndBBFloat16ComponentsINTEL ||
1645 CoopOperands &
1646 SPIRV::CooperativeMatrixOperands::MatrixCBFloat16ComponentsINTEL ||
1647 CoopOperands & SPIRV::CooperativeMatrixOperands::
1648 MatrixResultBFloat16ComponentsINTEL) {
1649 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
1650 report_fatal_error("***BF16ComponentsINTEL type interpretations "
1651 "require the following SPIR-V extension: "
1652 "SPV_INTEL_joint_matrix",
1653 false);
1654 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
1655 Reqs.addCapability(
1656 SPIRV::Capability::CooperativeMatrixBFloat16ComponentTypeINTEL);
1657 }
1658 break;
1659 }
1660 case SPIRV::OpCooperativeMatrixLoadKHR:
1661 case SPIRV::OpCooperativeMatrixStoreKHR:
1662 case SPIRV::OpCooperativeMatrixLoadCheckedINTEL:
1663 case SPIRV::OpCooperativeMatrixStoreCheckedINTEL:
1664 case SPIRV::OpCooperativeMatrixPrefetchINTEL: {
1665 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix))
1666 report_fatal_error("Cooperative matrix instructions require the "
1667 "following SPIR-V extension: "
1668 "SPV_KHR_cooperative_matrix",
1669 false);
1670 Reqs.addExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix);
1671 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixKHR);
1672
1673 // Check Layout operand in case if it's not a standard one and add the
1674 // appropriate capability.
1675 std::unordered_map<unsigned, unsigned> LayoutToInstMap = {
1676 {SPIRV::OpCooperativeMatrixLoadKHR, 3},
1677 {SPIRV::OpCooperativeMatrixStoreKHR, 2},
1678 {SPIRV::OpCooperativeMatrixLoadCheckedINTEL, 5},
1679 {SPIRV::OpCooperativeMatrixStoreCheckedINTEL, 4},
1680 {SPIRV::OpCooperativeMatrixPrefetchINTEL, 4}};
1681
1682 const auto OpCode = MI.getOpcode();
1683 const unsigned LayoutNum = LayoutToInstMap[OpCode];
1684 Register RegLayout = MI.getOperand(LayoutNum).getReg();
1685 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1686 MachineInstr *MILayout = MRI.getUniqueVRegDef(RegLayout);
1687 if (MILayout->getOpcode() == SPIRV::OpConstantI) {
1688 const unsigned LayoutVal = MILayout->getOperand(2).getImm();
1689 if (LayoutVal ==
1690 static_cast<unsigned>(SPIRV::CooperativeMatrixLayout::PackedINTEL)) {
1691 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
1692 report_fatal_error("PackedINTEL layout require the following SPIR-V "
1693 "extension: SPV_INTEL_joint_matrix",
1694 false);
1695 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
1696 Reqs.addCapability(SPIRV::Capability::PackedCooperativeMatrixINTEL);
1697 }
1698 }
1699
1700 // Nothing to do.
1701 if (OpCode == SPIRV::OpCooperativeMatrixLoadKHR ||
1702 OpCode == SPIRV::OpCooperativeMatrixStoreKHR)
1703 break;
1704
1705 std::string InstName;
1706 switch (OpCode) {
1707 case SPIRV::OpCooperativeMatrixPrefetchINTEL:
1708 InstName = "OpCooperativeMatrixPrefetchINTEL";
1709 break;
1710 case SPIRV::OpCooperativeMatrixLoadCheckedINTEL:
1711 InstName = "OpCooperativeMatrixLoadCheckedINTEL";
1712 break;
1713 case SPIRV::OpCooperativeMatrixStoreCheckedINTEL:
1714 InstName = "OpCooperativeMatrixStoreCheckedINTEL";
1715 break;
1716 }
1717
1718 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix)) {
1719 const std::string ErrorMsg =
1720 InstName + " instruction requires the "
1721 "following SPIR-V extension: SPV_INTEL_joint_matrix";
1722 report_fatal_error(ErrorMsg.c_str(), false);
1723 }
1724 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
1725 if (OpCode == SPIRV::OpCooperativeMatrixPrefetchINTEL) {
1726 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixPrefetchINTEL);
1727 break;
1728 }
1729 Reqs.addCapability(
1730 SPIRV::Capability::CooperativeMatrixCheckedInstructionsINTEL);
1731 break;
1732 }
1733 case SPIRV::OpCooperativeMatrixConstructCheckedINTEL:
1734 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
1735 report_fatal_error("OpCooperativeMatrixConstructCheckedINTEL "
1736 "instructions require the following SPIR-V extension: "
1737 "SPV_INTEL_joint_matrix",
1738 false);
1739 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
1740 Reqs.addCapability(
1741 SPIRV::Capability::CooperativeMatrixCheckedInstructionsINTEL);
1742 break;
1743 case SPIRV::OpCooperativeMatrixGetElementCoordINTEL:
1744 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
1745 report_fatal_error("OpCooperativeMatrixGetElementCoordINTEL requires the "
1746 "following SPIR-V extension: SPV_INTEL_joint_matrix",
1747 false);
1748 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
1749 Reqs.addCapability(
1750 SPIRV::Capability::CooperativeMatrixInvocationInstructionsINTEL);
1751 break;
1752 case SPIRV::OpConvertHandleToImageINTEL:
1753 case SPIRV::OpConvertHandleToSamplerINTEL:
1754 case SPIRV::OpConvertHandleToSampledImageINTEL:
1755 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bindless_images))
1756 report_fatal_error("OpConvertHandleTo[Image/Sampler/SampledImage]INTEL "
1757 "instructions require the following SPIR-V extension: "
1758 "SPV_INTEL_bindless_images",
1759 false);
1760 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bindless_images);
1761 Reqs.addCapability(SPIRV::Capability::BindlessImagesINTEL);
1762 break;
1763 case SPIRV::OpSubgroup2DBlockLoadINTEL:
1764 case SPIRV::OpSubgroup2DBlockLoadTransposeINTEL:
1765 case SPIRV::OpSubgroup2DBlockLoadTransformINTEL:
1766 case SPIRV::OpSubgroup2DBlockPrefetchINTEL:
1767 case SPIRV::OpSubgroup2DBlockStoreINTEL: {
1768 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_2d_block_io))
1769 report_fatal_error("OpSubgroup2DBlock[Load/LoadTranspose/LoadTransform/"
1770 "Prefetch/Store]INTEL instructions require the "
1771 "following SPIR-V extension: SPV_INTEL_2d_block_io",
1772 false);
1773 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_2d_block_io);
1774 Reqs.addCapability(SPIRV::Capability::Subgroup2DBlockIOINTEL);
1775
1776 const auto OpCode = MI.getOpcode();
1777 if (OpCode == SPIRV::OpSubgroup2DBlockLoadTransposeINTEL) {
1778 Reqs.addCapability(SPIRV::Capability::Subgroup2DBlockTransposeINTEL);
1779 break;
1780 }
1781 if (OpCode == SPIRV::OpSubgroup2DBlockLoadTransformINTEL) {
1782 Reqs.addCapability(SPIRV::Capability::Subgroup2DBlockTransformINTEL);
1783 break;
1784 }
1785 break;
1786 }
1787 case SPIRV::OpKill: {
1788 Reqs.addCapability(SPIRV::Capability::Shader);
1789 } break;
1790 case SPIRV::OpDemoteToHelperInvocation:
1791 Reqs.addCapability(SPIRV::Capability::DemoteToHelperInvocation);
1792
1793 if (ST.canUseExtension(
1794 SPIRV::Extension::SPV_EXT_demote_to_helper_invocation)) {
1795 if (!ST.isAtLeastSPIRVVer(llvm::VersionTuple(1, 6)))
1796 Reqs.addExtension(
1797 SPIRV::Extension::SPV_EXT_demote_to_helper_invocation);
1798 }
1799 break;
1800 case SPIRV::OpSDot:
1801 case SPIRV::OpUDot:
1802 case SPIRV::OpSUDot:
1803 case SPIRV::OpSDotAccSat:
1804 case SPIRV::OpUDotAccSat:
1805 case SPIRV::OpSUDotAccSat:
1806 AddDotProductRequirements(MI, Reqs, ST);
1807 break;
1808 case SPIRV::OpImageRead: {
1809 Register ImageReg = MI.getOperand(2).getReg();
1810 SPIRVType *TypeDef = ST.getSPIRVGlobalRegistry()->getResultType(
1811 ImageReg, const_cast<MachineFunction *>(MI.getMF()));
1812 // OpImageRead and OpImageWrite can use Unknown Image Formats
1813 // when the Kernel capability is declared. In the OpenCL environment we are
1814 // not allowed to produce
1815 // StorageImageReadWithoutFormat/StorageImageWriteWithoutFormat, see
1816 // https://github.com/KhronosGroup/SPIRV-Headers/issues/487
1817
1818 if (isImageTypeWithUnknownFormat(TypeDef) && ST.isShader())
1819 Reqs.addCapability(SPIRV::Capability::StorageImageReadWithoutFormat);
1820 break;
1821 }
1822 case SPIRV::OpImageWrite: {
1823 Register ImageReg = MI.getOperand(0).getReg();
1824 SPIRVType *TypeDef = ST.getSPIRVGlobalRegistry()->getResultType(
1825 ImageReg, const_cast<MachineFunction *>(MI.getMF()));
1826 // OpImageRead and OpImageWrite can use Unknown Image Formats
1827 // when the Kernel capability is declared. In the OpenCL environment we are
1828 // not allowed to produce
1829 // StorageImageReadWithoutFormat/StorageImageWriteWithoutFormat, see
1830 // https://github.com/KhronosGroup/SPIRV-Headers/issues/487
1831
1832 if (isImageTypeWithUnknownFormat(TypeDef) && ST.isShader())
1833 Reqs.addCapability(SPIRV::Capability::StorageImageWriteWithoutFormat);
1834 break;
1835 }
1836 case SPIRV::OpTypeStructContinuedINTEL:
1837 case SPIRV::OpConstantCompositeContinuedINTEL:
1838 case SPIRV::OpSpecConstantCompositeContinuedINTEL:
1839 case SPIRV::OpCompositeConstructContinuedINTEL: {
1840 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_long_composites))
1842 "Continued instructions require the "
1843 "following SPIR-V extension: SPV_INTEL_long_composites",
1844 false);
1845 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_long_composites);
1846 Reqs.addCapability(SPIRV::Capability::LongCompositesINTEL);
1847 break;
1848 }
1849 case SPIRV::OpSubgroupMatrixMultiplyAccumulateINTEL: {
1850 if (!ST.canUseExtension(
1851 SPIRV::Extension::SPV_INTEL_subgroup_matrix_multiply_accumulate))
1853 "OpSubgroupMatrixMultiplyAccumulateINTEL instruction requires the "
1854 "following SPIR-V "
1855 "extension: SPV_INTEL_subgroup_matrix_multiply_accumulate",
1856 false);
1857 Reqs.addExtension(
1858 SPIRV::Extension::SPV_INTEL_subgroup_matrix_multiply_accumulate);
1859 Reqs.addCapability(
1860 SPIRV::Capability::SubgroupMatrixMultiplyAccumulateINTEL);
1861 break;
1862 }
1863 case SPIRV::OpBitwiseFunctionINTEL: {
1864 if (!ST.canUseExtension(
1865 SPIRV::Extension::SPV_INTEL_ternary_bitwise_function))
1867 "OpBitwiseFunctionINTEL instruction requires the following SPIR-V "
1868 "extension: SPV_INTEL_ternary_bitwise_function",
1869 false);
1870 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_ternary_bitwise_function);
1871 Reqs.addCapability(SPIRV::Capability::TernaryBitwiseFunctionINTEL);
1872 break;
1873 }
1874 case SPIRV::OpCopyMemorySized: {
1875 Reqs.addCapability(SPIRV::Capability::Addresses);
1876 // TODO: Add UntypedPointersKHR when implemented.
1877 break;
1878 }
1879
1880 default:
1881 break;
1882 }
1883
1884 // If we require capability Shader, then we can remove the requirement for
1885 // the BitInstructions capability, since Shader is a superset capability
1886 // of BitInstructions.
1887 Reqs.removeCapabilityIf(SPIRV::Capability::BitInstructions,
1888 SPIRV::Capability::Shader);
1889}
1890
1891static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI,
1892 MachineModuleInfo *MMI, const SPIRVSubtarget &ST) {
1893 // Collect requirements for existing instructions.
1894 for (auto F = M.begin(), E = M.end(); F != E; ++F) {
1896 if (!MF)
1897 continue;
1898 for (const MachineBasicBlock &MBB : *MF)
1899 for (const MachineInstr &MI : MBB)
1900 addInstrRequirements(MI, MAI.Reqs, ST);
1901 }
1902 // Collect requirements for OpExecutionMode instructions.
1903 auto Node = M.getNamedMetadata("spirv.ExecutionMode");
1904 if (Node) {
1905 bool RequireFloatControls = false, RequireFloatControls2 = false,
1906 VerLower14 = !ST.isAtLeastSPIRVVer(VersionTuple(1, 4));
1907 bool HasFloatControls2 =
1908 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_float_controls2);
1909 for (unsigned i = 0; i < Node->getNumOperands(); i++) {
1910 MDNode *MDN = cast<MDNode>(Node->getOperand(i));
1911 const MDOperand &MDOp = MDN->getOperand(1);
1912 if (auto *CMeta = dyn_cast<ConstantAsMetadata>(MDOp)) {
1913 Constant *C = CMeta->getValue();
1914 if (ConstantInt *Const = dyn_cast<ConstantInt>(C)) {
1915 auto EM = Const->getZExtValue();
1916 // SPV_KHR_float_controls is not available until v1.4:
1917 // add SPV_KHR_float_controls if the version is too low
1918 switch (EM) {
1919 case SPIRV::ExecutionMode::DenormPreserve:
1920 case SPIRV::ExecutionMode::DenormFlushToZero:
1921 case SPIRV::ExecutionMode::SignedZeroInfNanPreserve:
1922 case SPIRV::ExecutionMode::RoundingModeRTE:
1923 case SPIRV::ExecutionMode::RoundingModeRTZ:
1924 RequireFloatControls = VerLower14;
1926 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
1927 break;
1928 case SPIRV::ExecutionMode::RoundingModeRTPINTEL:
1929 case SPIRV::ExecutionMode::RoundingModeRTNINTEL:
1930 case SPIRV::ExecutionMode::FloatingPointModeALTINTEL:
1931 case SPIRV::ExecutionMode::FloatingPointModeIEEEINTEL:
1932 if (HasFloatControls2) {
1933 RequireFloatControls2 = true;
1935 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
1936 }
1937 break;
1938 default:
1940 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
1941 }
1942 }
1943 }
1944 }
1945 if (RequireFloatControls &&
1946 ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls))
1947 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls);
1948 if (RequireFloatControls2)
1949 MAI.Reqs.addExtension(SPIRV::Extension::SPV_INTEL_float_controls2);
1950 }
1951 for (auto FI = M.begin(), E = M.end(); FI != E; ++FI) {
1952 const Function &F = *FI;
1953 if (F.isDeclaration())
1954 continue;
1955 if (F.getMetadata("reqd_work_group_size"))
1957 SPIRV::OperandCategory::ExecutionModeOperand,
1958 SPIRV::ExecutionMode::LocalSize, ST);
1959 if (F.getFnAttribute("hlsl.numthreads").isValid()) {
1961 SPIRV::OperandCategory::ExecutionModeOperand,
1962 SPIRV::ExecutionMode::LocalSize, ST);
1963 }
1964 if (F.getMetadata("work_group_size_hint"))
1966 SPIRV::OperandCategory::ExecutionModeOperand,
1967 SPIRV::ExecutionMode::LocalSizeHint, ST);
1968 if (F.getMetadata("intel_reqd_sub_group_size"))
1970 SPIRV::OperandCategory::ExecutionModeOperand,
1971 SPIRV::ExecutionMode::SubgroupSize, ST);
1972 if (F.getMetadata("vec_type_hint"))
1974 SPIRV::OperandCategory::ExecutionModeOperand,
1975 SPIRV::ExecutionMode::VecTypeHint, ST);
1976
1977 if (F.hasOptNone()) {
1978 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_optnone)) {
1979 MAI.Reqs.addExtension(SPIRV::Extension::SPV_INTEL_optnone);
1980 MAI.Reqs.addCapability(SPIRV::Capability::OptNoneINTEL);
1981 } else if (ST.canUseExtension(SPIRV::Extension::SPV_EXT_optnone)) {
1982 MAI.Reqs.addExtension(SPIRV::Extension::SPV_EXT_optnone);
1983 MAI.Reqs.addCapability(SPIRV::Capability::OptNoneEXT);
1984 }
1985 }
1986 }
1987}
1988
1989static unsigned getFastMathFlags(const MachineInstr &I) {
1990 unsigned Flags = SPIRV::FPFastMathMode::None;
1991 if (I.getFlag(MachineInstr::MIFlag::FmNoNans))
1992 Flags |= SPIRV::FPFastMathMode::NotNaN;
1993 if (I.getFlag(MachineInstr::MIFlag::FmNoInfs))
1994 Flags |= SPIRV::FPFastMathMode::NotInf;
1995 if (I.getFlag(MachineInstr::MIFlag::FmNsz))
1996 Flags |= SPIRV::FPFastMathMode::NSZ;
1997 if (I.getFlag(MachineInstr::MIFlag::FmArcp))
1998 Flags |= SPIRV::FPFastMathMode::AllowRecip;
2000 Flags |= SPIRV::FPFastMathMode::Fast;
2001 return Flags;
2002}
2003
2004static bool isFastMathMathModeAvailable(const SPIRVSubtarget &ST) {
2005 if (ST.isKernel())
2006 return true;
2007 if (ST.getSPIRVVersion() < VersionTuple(1, 2))
2008 return false;
2009 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2);
2010}
2011
2012static void handleMIFlagDecoration(MachineInstr &I, const SPIRVSubtarget &ST,
2013 const SPIRVInstrInfo &TII,
2015 if (I.getFlag(MachineInstr::MIFlag::NoSWrap) && TII.canUseNSW(I) &&
2016 getSymbolicOperandRequirements(SPIRV::OperandCategory::DecorationOperand,
2017 SPIRV::Decoration::NoSignedWrap, ST, Reqs)
2018 .IsSatisfiable) {
2019 buildOpDecorate(I.getOperand(0).getReg(), I, TII,
2020 SPIRV::Decoration::NoSignedWrap, {});
2021 }
2022 if (I.getFlag(MachineInstr::MIFlag::NoUWrap) && TII.canUseNUW(I) &&
2023 getSymbolicOperandRequirements(SPIRV::OperandCategory::DecorationOperand,
2024 SPIRV::Decoration::NoUnsignedWrap, ST,
2025 Reqs)
2026 .IsSatisfiable) {
2027 buildOpDecorate(I.getOperand(0).getReg(), I, TII,
2028 SPIRV::Decoration::NoUnsignedWrap, {});
2029 }
2030 if (!TII.canUseFastMathFlags(I))
2031 return;
2032 unsigned FMFlags = getFastMathFlags(I);
2033 if (FMFlags == SPIRV::FPFastMathMode::None)
2034 return;
2035
2036 if (isFastMathMathModeAvailable(ST)) {
2037 Register DstReg = I.getOperand(0).getReg();
2038 buildOpDecorate(DstReg, I, TII, SPIRV::Decoration::FPFastMathMode,
2039 {FMFlags});
2040 }
2041}
2042
2043// Walk all functions and add decorations related to MI flags.
2044static void addDecorations(const Module &M, const SPIRVInstrInfo &TII,
2045 MachineModuleInfo *MMI, const SPIRVSubtarget &ST,
2047 for (auto F = M.begin(), E = M.end(); F != E; ++F) {
2049 if (!MF)
2050 continue;
2051 for (auto &MBB : *MF)
2052 for (auto &MI : MBB)
2053 handleMIFlagDecoration(MI, ST, TII, MAI.Reqs);
2054 }
2055}
2056
2057static void addMBBNames(const Module &M, const SPIRVInstrInfo &TII,
2058 MachineModuleInfo *MMI, const SPIRVSubtarget &ST,
2060 for (auto F = M.begin(), E = M.end(); F != E; ++F) {
2062 if (!MF)
2063 continue;
2065 for (auto &MBB : *MF) {
2066 if (!MBB.hasName() || MBB.empty())
2067 continue;
2068 // Emit basic block names.
2069 Register Reg = MRI.createGenericVirtualRegister(LLT::scalar(64));
2070 MRI.setRegClass(Reg, &SPIRV::IDRegClass);
2071 buildOpName(Reg, MBB.getName(), *std::prev(MBB.end()), TII);
2072 MCRegister GlobalReg = MAI.getOrCreateMBBRegister(MBB);
2073 MAI.setRegisterAlias(MF, Reg, GlobalReg);
2074 }
2075 }
2076}
2077
2078// patching Instruction::PHI to SPIRV::OpPhi
2079static void patchPhis(const Module &M, SPIRVGlobalRegistry *GR,
2080 const SPIRVInstrInfo &TII, MachineModuleInfo *MMI) {
2081 for (auto F = M.begin(), E = M.end(); F != E; ++F) {
2083 if (!MF)
2084 continue;
2085 for (auto &MBB : *MF) {
2086 for (MachineInstr &MI : MBB.phis()) {
2087 MI.setDesc(TII.get(SPIRV::OpPhi));
2088 Register ResTypeReg = GR->getSPIRVTypeID(
2089 GR->getSPIRVTypeForVReg(MI.getOperand(0).getReg(), MF));
2090 MI.insert(MI.operands_begin() + 1,
2091 {MachineOperand::CreateReg(ResTypeReg, false)});
2092 }
2093 }
2094
2095 MF->getProperties().setNoPHIs();
2096 }
2097}
2098
2100
2102 AU.addRequired<TargetPassConfig>();
2103 AU.addRequired<MachineModuleInfoWrapperPass>();
2104}
2105
2107 SPIRVTargetMachine &TM =
2109 ST = TM.getSubtargetImpl();
2110 GR = ST->getSPIRVGlobalRegistry();
2111 TII = ST->getInstrInfo();
2112
2114
2115 setBaseInfo(M);
2116
2117 patchPhis(M, GR, *TII, MMI);
2118
2119 addMBBNames(M, *TII, MMI, *ST, MAI);
2120 addDecorations(M, *TII, MMI, *ST, MAI);
2121
2122 collectReqs(M, MAI, MMI, *ST);
2123
2124 // Process type/const/global var/func decl instructions, number their
2125 // destination registers from 0 to N, collect Extensions and Capabilities.
2126 collectReqs(M, MAI, MMI, *ST);
2127 collectDeclarations(M);
2128
2129 // Number rest of registers from N+1 onwards.
2130 numberRegistersGlobally(M);
2131
2132 // Collect OpName, OpEntryPoint, OpDecorate etc, process other instructions.
2133 processOtherInstrs(M);
2134
2135 // If there are no entry points, we need the Linkage capability.
2136 if (MAI.MS[SPIRV::MB_EntryPoints].empty())
2137 MAI.Reqs.addCapability(SPIRV::Capability::Linkage);
2138
2139 // Set maximum ID used.
2140 GR->setBound(MAI.MaxID);
2141
2142 return false;
2143}
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
ReachingDefInfo InstSet & ToRemove
MachineBasicBlock & MBB
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
#define DEBUG_TYPE
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:55
#define I(x, y, z)
Definition MD5.cpp:58
Register Reg
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
#define ATOM_FLT_REQ_EXT_MSG(ExtName)
static cl::opt< bool > SPVDumpDeps("spv-dump-deps", cl::desc("Dump MIR with SPIR-V dependencies info"), cl::Optional, cl::init(false))
unsigned unsigned DefaultVal
unsigned OpIndex
static cl::list< SPIRV::Capability::Capability > AvoidCapabilities("avoid-spirv-capabilities", cl::desc("SPIR-V capabilities to avoid if there are " "other options enabling a feature"), cl::ZeroOrMore, cl::Hidden, cl::values(clEnumValN(SPIRV::Capability::Shader, "Shader", "SPIR-V Shader capability")))
This file contains some templates that are useful if you are working with the STL at all.
#define LLVM_DEBUG(...)
Definition Debug.h:114
Target-Independent Code Generator Pass Configuration Options pass.
The Input class is used to parse a yaml document into in-memory structs and vectors.
This is the shared class of boolean and integer constants.
Definition Constants.h:87
This is an important base class in LLVM.
Definition Constant.h:43
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
Wrapper class representing physical registers. Should be passed by value.
Definition MCRegister.h:33
constexpr bool isValid() const
Definition MCRegister.h:76
Metadata node.
Definition Metadata.h:1077
const MDOperand & getOperand(unsigned I) const
Definition Metadata.h:1441
unsigned getNumOperands() const
Return number of MDNode operands.
Definition Metadata.h:1447
Tracking metadata reference owned by Metadata.
Definition Metadata.h:899
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const MachineFunctionProperties & getProperties() const
Get the function properties.
Register getReg(unsigned Idx) const
Get the register for the operand index.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
LLVM_ABI const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
const MachineOperand & getOperand(unsigned i) const
This class contains meta information specific to a module.
LLVM_ABI MachineFunction * getMachineFunction(const Function &F) const
Returns the MachineFunction associated to IR function F if there is one, otherwise nullptr.
MachineOperand class - Representation of each machine instruction operand.
unsigned getSubReg() const
int64_t getImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
LLVM_ABI void print(raw_ostream &os, const TargetRegisterInfo *TRI=nullptr) const
Print the MachineOperand to os.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
virtual void print(raw_ostream &OS, const Module *M) const
print - Print out the internal state of the pass.
Definition Pass.cpp:140
AnalysisType & getAnalysis() const
getAnalysis<AnalysisType>() - This function is used by subclasses to get to the analysis information ...
Wrapper class representing virtual and physical registers.
Definition Register.h:19
constexpr bool isValid() const
Definition Register.h:107
SPIRVType * getSPIRVTypeForVReg(Register VReg, const MachineFunction *MF=nullptr) const
Register getSPIRVTypeID(const SPIRVType *SpirvType) const
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition SmallSet.h:133
bool contains(const T &V) const
Check if the SmallSet contains the given element.
Definition SmallSet.h:226
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
Definition SmallSet.h:181
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
iterator insert(iterator I, T &&Elt)
void push_back(const T &Elt)
Target-Independent Code Generator Pass Configuration Options.
Represents a version number in the form major[.minor[.subminor[.build]]].
bool empty() const
Determine whether this version information is empty (e.g., all version components are zero).
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
Definition ilist_node.h:355
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > extract(Y &&MD)
Extract a Value from Metadata.
Definition Metadata.h:666
NodeAddr< InstrNode * > Instr
Definition RDFGraph.h:389
This is an optimization pass for GlobalISel generic memory operations.
void buildOpName(Register Target, const StringRef &Name, MachineIRBuilder &MIRBuilder)
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
std::string getStringImm(const MachineInstr &MI, unsigned StartIndex)
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1705
hash_code hash_value(const FixedPointSemantics &Val)
ExtensionList getSymbolicOperandExtensions(SPIRV::OperandCategory::OperandCategory Category, uint32_t Value)
CapabilityList getSymbolicOperandCapabilities(SPIRV::OperandCategory::OperandCategory Category, uint32_t Value)
SmallVector< SPIRV::Extension::Extension, 8 > ExtensionList
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:649
SmallVector< size_t > InstrSignature
VersionTuple getSymbolicOperandMaxVersion(SPIRV::OperandCategory::OperandCategory Category, uint32_t Value)
void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, SPIRV::Decoration::Decoration Dec, const std::vector< uint32_t > &DecArgs, StringRef StrImm)
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
CapabilityList getCapabilitiesEnabledByExtension(SPIRV::Extension::Extension Extension)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:167
const MachineInstr SPIRVType
std::string getSymbolicOperandMnemonic(SPIRV::OperandCategory::OperandCategory Category, int32_t Value)
DWARFExpression::Operation Op
VersionTuple getSymbolicOperandMinVersion(SPIRV::OperandCategory::OperandCategory Category, uint32_t Value)
constexpr unsigned BitWidth
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:565
SmallVector< SPIRV::Capability::Capability, 8 > CapabilityList
std::set< InstrSignature > InstrTraces
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition Hashing.h:584
std::map< SmallVector< size_t >, unsigned > InstrGRegsMap
#define N
SmallSet< SPIRV::Capability::Capability, 4 > S
static struct SPIRV::ModuleAnalysisInfo MAI
bool runOnModule(Module &M) override
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
void setSkipEmission(const MachineInstr *MI)
MCRegister getRegisterAlias(const MachineFunction *MF, Register Reg)
MCRegister getOrCreateMBBRegister(const MachineBasicBlock &MBB)
InstrList MS[NUM_MODULE_SECTIONS]
void setRegisterAlias(const MachineFunction *MF, Register Reg, MCRegister AliasReg)
void addCapabilities(const CapabilityList &ToAdd)
bool isCapabilityAvailable(Capability::Capability Cap) const
void checkSatisfiable(const SPIRVSubtarget &ST) const
void getAndAddRequirements(SPIRV::OperandCategory::OperandCategory Category, uint32_t i, const SPIRVSubtarget &ST)
void addExtension(Extension::Extension ToAdd)
void initAvailableCapabilities(const SPIRVSubtarget &ST)
void removeCapabilityIf(const Capability::Capability ToRemove, const Capability::Capability IfPresent)
void addCapability(Capability::Capability ToAdd)
void addAvailableCaps(const CapabilityList &ToAdd)
void addRequirements(const Requirements &Req)
const std::optional< Capability::Capability > Cap