Thanks to visit codestin.com
Credit goes to llvm.org

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