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
48};
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 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();
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
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;
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);
312 return false;
313 }
314 }
315 return TII->isTypeDeclInstr(MI) || TII->isConstantInstr(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();
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)
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;
443 It->second = GReg;
444 if (!IsFunDef)
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;
457 It->second = GReg;
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;
472 It->second = GReg;
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) {
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()));
508 break;
509 case SPIRV::OpCapability:
510 MAI.Reqs.addCapability(SPIRV::Capability::Capability(DefMO.getImm()));
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;
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;
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;
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))) {
879 addAvailableCaps(
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 =
2108 getAnalysis<TargetPassConfig>().getTM<SPIRVTargetMachine>();
2109 ST = TM.getSubtargetImpl();
2110 GR = ST->getSPIRVGlobalRegistry();
2111 TII = ST->getInstrInfo();
2112
2113 MMI = &getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
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
ReachingDefAnalysis InstSet & ToRemove
MachineBasicBlock & MBB
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
Definition: CommandLine.h:687
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
uint64_t Addr
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
#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
#define DEBUG_TYPE
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")))
spirv structurize SPIRV
This file contains some templates that are useful if you are working with the STL at all.
#define LLVM_DEBUG(...)
Definition: Debug.h:119
Target-Independent Code Generator Pass Configuration Options pass.
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
This class represents an Operation in the Expression.
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
Definition: LowLevelType.h:43
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:1445
unsigned getNumOperands() const
Return number of MDNode operands.
Definition: Metadata.h:1451
Tracking metadata reference owned by Metadata.
Definition: Metadata.h:899
iterator_range< iterator > phis()
Returns a range that iterates over the phis in the basic block.
LLVM_ABI bool hasName() const
Check if there is a name of corresponding LLVM basic block.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
LLVM_ABI StringRef getName() const
Return the name of the corresponding LLVM basic block, or an empty string.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Register getReg(unsigned Idx) const
Get the register for the operand index.
Representation of each machine instruction.
Definition: MachineInstr.h:72
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
Definition: MachineInstr.h:587
const MachineBasicBlock * getParent() const
Definition: MachineInstr.h:359
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
Definition: MachineInstr.h:595
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
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
const Value * getGlobalObject(const MachineFunction *MF, Register R)
const MachineOperand * getFunctionDefinitionByUse(const MachineOperand *Use)
Register getSPIRVTypeID(const SPIRVType *SpirvType) const
bool isConstantInstr(const MachineInstr &MI) const
bool isInlineAsmDefInstr(const MachineInstr &MI) const
bool isTypeDeclInstr(const MachineInstr &MI) const
bool isSpecConstantInstr(const MachineInstr &MI) const
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition: SmallSet.h:134
void insert_range(Range &&R)
Definition: SmallSet.h:194
bool contains(const T &V) const
Check if the SmallSet contains the given element.
Definition: SmallSet.h:227
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:182
bool empty() const
Definition: SmallVector.h:82
size_t size() const
Definition: SmallVector.h:79
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
Definition: SmallVector.h:684
iterator insert(iterator I, T &&Elt)
Definition: SmallVector.h:806
void push_back(const T &Elt)
Definition: SmallVector.h:414
std::pair< typename Base::iterator, bool > insert(StringRef key)
Definition: StringSet.h:39
Target-Independent Code Generator Pass Configuration Options.
Target - Wrapper for Target specific information.
LLVM Value Representation.
Definition: Value.h:75
Represents a version number in the form major[.minor[.subminor[.build]]].
Definition: VersionTuple.h:30
bool empty() const
Determine whether this version information is empty (e.g., all version components are zero).
Definition: VersionTuple.h:67
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
Definition: ilist_node.h:359
#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
Reg
All possible values of the reg field in the ModR/M byte.
StorageClass
Definition: XCOFF.h:171
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
Definition: CommandLine.h:712
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:444
NodeAddr< InstrNode * > Instr
Definition: RDFGraph.h:389
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
void buildOpName(Register Target, const StringRef &Name, MachineIRBuilder &MIRBuilder)
Definition: SPIRVUtils.cpp:113
std::string getStringImm(const MachineInstr &MI, unsigned StartIndex)
Definition: SPIRVUtils.cpp:79
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:1744
hash_code hash_value(const FixedPointSemantics &Val)
Definition: APFixedPoint.h:137
ExtensionList getSymbolicOperandExtensions(SPIRV::OperandCategory::OperandCategory Category, uint32_t Value)
CapabilityList getSymbolicOperandCapabilities(SPIRV::OperandCategory::OperandCategory Category, uint32_t Value)
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)
Definition: SPIRVUtils.cpp:140
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
Definition: SPIRVUtils.cpp:976
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
std::set< InstrSignature > InstrTraces
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition: Error.cpp:167
std::string getSymbolicOperandMnemonic(SPIRV::OperandCategory::OperandCategory Category, int32_t Value)
VersionTuple getSymbolicOperandMinVersion(SPIRV::OperandCategory::OperandCategory Category, uint32_t Value)
constexpr unsigned BitWidth
Definition: BitmaskEnum.h:223
std::map< SmallVector< size_t >, unsigned > InstrGRegsMap
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition: Hashing.h:595
#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...
SmallVector< const MachineInstr *, 4 > GlobalVarList
DenseMap< unsigned, MCRegister > ExtInstSetMap
void setSkipEmission(const MachineInstr *MI)
DenseSet< const MachineInstr * > InstrsToDelete
bool hasRegisterAlias(const MachineFunction *MF, Register Reg)
DenseMap< const Function *, MCRegister > FuncMap
MCRegister getRegisterAlias(const MachineFunction *MF, Register Reg)
bool getSkipEmission(const MachineInstr *MI)
MCRegister getOrCreateMBBRegister(const MachineBasicBlock &MBB)
InstrList MS[NUM_MODULE_SECTIONS]
AddressingModel::AddressingModel Addr
void setRegisterAlias(const MachineFunction *MF, Register Reg, MCRegister AliasReg)
SourceLanguage::SourceLanguage SrcLang
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