LLVM 24.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// TODO: Per LLVM best practices, the report_fatal_error (deprecated) /
18// ReportFatalUsageError calls in this file should be replaced with the
19// Diagnostic infrastructure (e.g. the reportUnsupported function below).
20
21#include "SPIRVModuleAnalysis.h"
24#include "SPIRV.h"
25#include "SPIRVSubtarget.h"
26#include "SPIRVTargetMachine.h"
27#include "SPIRVUtils.h"
28#include "llvm/ADT/STLExtras.h"
33
34using namespace llvm;
35
36#define DEBUG_TYPE "spirv-module-analysis"
37
38static cl::opt<bool>
39 SPVDumpDeps("spv-dump-deps",
40 cl::desc("Dump MIR with SPIR-V dependencies info"),
41 cl::init(false));
42
44 AvoidCapabilities("avoid-spirv-capabilities",
45 cl::desc("SPIR-V capabilities to avoid if there are "
46 "other options enabling a feature"),
48 cl::values(clEnumValN(SPIRV::Capability::Shader, "Shader",
49 "SPIR-V Shader capability")));
50// Use sets instead of cl::list to check "if contains" condition
55
57
59 "SPIRV module analysis", true, true)
60
62 const Function &Func = MI.getMF()->getFunction();
63 Func.getContext().diagnose(
64 DiagnosticInfoUnsupported(Func, Msg, MI.getDebugLoc()));
65}
66
67// Retrieve an unsigned from an MDNode with a list of them as operands.
68static unsigned getMetadataUInt(MDNode *MdNode, unsigned OpIndex,
69 unsigned DefaultVal = 0) {
70 if (MdNode && OpIndex < MdNode->getNumOperands()) {
71 const auto &Op = MdNode->getOperand(OpIndex);
72 return mdconst::extract<ConstantInt>(Op)->getZExtValue();
73 }
74 return DefaultVal;
75}
76
78getSymbolicOperandRequirements(SPIRV::OperandCategory::OperandCategory Category,
79 unsigned i, const SPIRVSubtarget &ST,
81 // A set of capabilities to avoid if there is another option.
82 AvoidCapabilitiesSet AvoidCaps;
83 if (!ST.isShader())
84 AvoidCaps.S.insert(SPIRV::Capability::Shader);
85 else
86 AvoidCaps.S.insert(SPIRV::Capability::Kernel);
87
88 VersionTuple ReqMinVer = getSymbolicOperandMinVersion(Category, i);
89 VersionTuple ReqMaxVer = getSymbolicOperandMaxVersion(Category, i);
90 VersionTuple SPIRVVersion = ST.getSPIRVVersion();
91 bool MinVerOK = SPIRVVersion.empty() || SPIRVVersion >= ReqMinVer;
92 bool MaxVerOK =
93 ReqMaxVer.empty() || SPIRVVersion.empty() || SPIRVVersion <= ReqMaxVer;
94 bool VerOK = MinVerOK && MaxVerOK;
96 ExtensionList ReqExts = getSymbolicOperandExtensions(Category, i);
97 // A met minimum version makes the extension unnecessary.
98 if (VerOK && !ReqMinVer.empty())
99 ReqExts.clear();
100 if (ReqCaps.empty()) {
101 if (ReqExts.empty()) {
102 if (VerOK)
103 return {true, {}, {}, ReqMinVer, ReqMaxVer};
104 return {false, {}, {}, VersionTuple(), VersionTuple()};
105 }
106 } else if (VerOK) {
107 if (ReqCaps.size() == 1) {
108 auto Cap = ReqCaps[0];
109 if (Reqs.isCapabilityAvailable(Cap)) {
111 SPIRV::OperandCategory::CapabilityOperand, Cap));
112 return {true, {Cap}, std::move(ReqExts), ReqMinVer, ReqMaxVer};
113 }
114 } else {
115 // By SPIR-V specification: "If an instruction, enumerant, or other
116 // feature specifies multiple enabling capabilities, only one such
117 // capability needs to be declared to use the feature." However, one
118 // capability may be preferred over another. We use command line
119 // argument(s) and AvoidCapabilities to avoid selection of certain
120 // capabilities if there are other options.
121 CapabilityList UseCaps;
122 for (auto Cap : ReqCaps)
123 if (Reqs.isCapabilityAvailable(Cap))
124 UseCaps.push_back(Cap);
125 for (size_t i = 0, Sz = UseCaps.size(); i < Sz; ++i) {
126 auto Cap = UseCaps[i];
127 if (i == Sz - 1 || !AvoidCaps.S.contains(Cap)) {
129 SPIRV::OperandCategory::CapabilityOperand, Cap));
130 return {true, {Cap}, std::move(ReqExts), ReqMinVer, ReqMaxVer};
131 }
132 }
133 }
134 }
135 // If there are no capabilities, or we can't satisfy the version or
136 // capability requirements, use the list of extensions (if the subtarget
137 // can handle them all). Without an extension the version must hold. An
138 // extension stands in for an unmet version.
139 if ((!ReqExts.empty() || VerOK) &&
140 llvm::all_of(ReqExts, [&ST](const SPIRV::Extension::Extension &Ext) {
141 return ST.canUseExtension(Ext);
142 })) {
143 if (VerOK)
144 return {true, {}, std::move(ReqExts), ReqMinVer, ReqMaxVer};
145 return {true, {}, std::move(ReqExts), VersionTuple(), VersionTuple()};
146 }
147 return {false, {}, {}, VersionTuple(), VersionTuple()};
148}
149
150void SPIRVModuleAnalysisImpl::setBaseInfo(const Module &M) {
151 MAI.MaxID = 0;
152 for (int i = 0; i < SPIRV::NUM_MODULE_SECTIONS; i++)
153 MAI.MS[i].clear();
154 MAI.RegisterAliasTable.clear();
155 MAI.InstrsToDelete.clear();
156 MAI.MBBNames.clear();
157 MAI.GlobalObjMap.clear();
158 MAI.GlobalVarList.clear();
159 MAI.ExtInstSetMap.clear();
160 MAI.InstrAuxDataRecords.clear();
161 MAI.DebugValueMIs.clear();
162 MAI.Reqs.clear();
163 MAI.Reqs.initAvailableCapabilities(*ST);
164
165 // TODO: determine memory model and source language from the configuratoin.
166 if (auto MemModel = M.getNamedMetadata("spirv.MemoryModel")) {
167 auto MemMD = MemModel->getOperand(0);
168 MAI.Addr = static_cast<SPIRV::AddressingModel::AddressingModel>(
169 getMetadataUInt(MemMD, 0));
170 MAI.Mem =
171 static_cast<SPIRV::MemoryModel::MemoryModel>(getMetadataUInt(MemMD, 1));
172 } else {
173 // TODO: Add support for VulkanMemoryModel.
174 MAI.Mem = ST->isShader() ? SPIRV::MemoryModel::GLSL450
175 : SPIRV::MemoryModel::OpenCL;
176 if (MAI.Mem == SPIRV::MemoryModel::OpenCL) {
177 unsigned PtrSize = ST->getPointerSize();
178 MAI.Addr = PtrSize == 32 ? SPIRV::AddressingModel::Physical32
179 : PtrSize == 64 ? SPIRV::AddressingModel::Physical64
180 : SPIRV::AddressingModel::Logical;
181 } else {
182 // TODO: Add support for PhysicalStorageBufferAddress.
183 MAI.Addr = SPIRV::AddressingModel::Logical;
184 }
185 }
186 // Get the OpenCL version number from metadata.
187 // TODO: support other source languages.
188 if (auto VerNode = M.getNamedMetadata("opencl.ocl.version")) {
189 MAI.SrcLang = SPIRV::SourceLanguage::OpenCL_C;
190 // Construct version literal in accordance with SPIRV-LLVM-Translator.
191 // TODO: support multiple OCL version metadata.
192 assert(VerNode->getNumOperands() > 0 && "Invalid SPIR");
193 auto VersionMD = VerNode->getOperand(0);
194 unsigned MajorNum = getMetadataUInt(VersionMD, 0, 2);
195 unsigned MinorNum = getMetadataUInt(VersionMD, 1);
196 unsigned RevNum = getMetadataUInt(VersionMD, 2);
197 // Prevent Major part of OpenCL version to be 0
198 MAI.SrcLangVersion =
199 (std::max(1U, MajorNum) * 100 + MinorNum) * 1000 + RevNum;
200 // When opencl.cxx.version is also present, validate compatibility
201 // and use C++ for OpenCL as source language with the C++ version.
202 if (auto *CxxVerNode = M.getNamedMetadata("opencl.cxx.version")) {
203 assert(CxxVerNode->getNumOperands() > 0 && "Invalid SPIR");
204 auto *CxxMD = CxxVerNode->getOperand(0);
205 unsigned CxxVer =
206 (getMetadataUInt(CxxMD, 0) * 100 + getMetadataUInt(CxxMD, 1)) * 1000 +
207 getMetadataUInt(CxxMD, 2);
208 if ((MAI.SrcLangVersion == 200000 && CxxVer == 100000) ||
209 (MAI.SrcLangVersion == 300000 && CxxVer == 202100000)) {
210 MAI.SrcLang = SPIRV::SourceLanguage::CPP_for_OpenCL;
211 MAI.SrcLangVersion = CxxVer;
212 } else {
214 "opencl cxx version is not compatible with opencl c version!");
215 }
216 }
217 } else {
218 // If there is no information about OpenCL version we are forced to generate
219 // OpenCL 1.0 by default for the OpenCL environment to avoid puzzling
220 // run-times with Unknown/0.0 version output. For a reference, LLVM-SPIRV
221 // Translator avoids potential issues with run-times in a similar manner.
222 if (!ST->isShader()) {
223 MAI.SrcLang = SPIRV::SourceLanguage::OpenCL_CPP;
224 MAI.SrcLangVersion = 100000;
225 } else {
226 MAI.SrcLang = SPIRV::SourceLanguage::Unknown;
227 MAI.SrcLangVersion = 0;
228 }
229 }
230
231 if (auto ExtNode = M.getNamedMetadata("opencl.used.extensions")) {
232 for (unsigned I = 0, E = ExtNode->getNumOperands(); I != E; ++I) {
233 MDNode *MD = ExtNode->getOperand(I);
234 if (!MD || MD->getNumOperands() == 0)
235 continue;
236 for (unsigned J = 0, N = MD->getNumOperands(); J != N; ++J)
237 MAI.SrcExt.insert(cast<MDString>(MD->getOperand(J))->getString());
238 }
239 }
240
241 // Update required capabilities for this memory model, addressing model and
242 // source language.
243 MAI.Reqs.getAndAddRequirements(SPIRV::OperandCategory::MemoryModelOperand,
244 MAI.Mem, *ST);
245 MAI.Reqs.getAndAddRequirements(SPIRV::OperandCategory::SourceLanguageOperand,
246 MAI.SrcLang, *ST);
247 MAI.Reqs.getAndAddRequirements(SPIRV::OperandCategory::AddressingModelOperand,
248 MAI.Addr, *ST);
249
250 if (MAI.Mem == SPIRV::MemoryModel::VulkanKHR)
251 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_vulkan_memory_model);
252
253 if (!ST->isShader()) {
254 // TODO: check if it's required by default.
255 MAI.ExtInstSetMap[static_cast<unsigned>(
256 SPIRV::InstructionSet::OpenCL_std)] = MAI.getNextIDRegister();
257 }
258}
259
260// Appends the signature of the decoration instructions that decorate R to
261// Signature.
263 InstrSignature &Signature) {
264 for (MachineInstr &UseMI : MRI.use_instructions(R)) {
265 // We don't handle OpDecorateId because getting the register alias for the
266 // ID can cause problems, and we do not need it for now.
267 if (UseMI.getOpcode() != SPIRV::OpDecorate &&
268 UseMI.getOpcode() != SPIRV::OpMemberDecorate)
269 continue;
270
271 for (unsigned I = 0; I < UseMI.getNumOperands(); ++I) {
272 const MachineOperand &MO = UseMI.getOperand(I);
273 if (MO.isReg())
274 continue;
275 Signature.push_back(hash_value(MO));
276 }
277 }
278}
279
280// Returns a representation of an instruction as a vector of MachineOperand
281// hash values, see llvm::hash_value(const MachineOperand &MO) for details.
282// This creates a signature of the instruction with the same content
283// that MachineOperand::isIdenticalTo uses for comparison.
286 bool UseDefReg) {
287 Register DefReg;
288 InstrSignature Signature{MI.getOpcode()};
289 for (unsigned i = 0; i < MI.getNumOperands(); ++i) {
290 // The only decorations that can be applied more than once to a given <id>
291 // or structure member are FuncParamAttr (38), UserSemantic (5635),
292 // CacheControlLoadINTEL (6442), and CacheControlStoreINTEL (6443). For all
293 // the rest of decorations, we will only add to the signature the Opcode,
294 // the id to which it applies, and the decoration id, disregarding any
295 // decoration flags. This will ensure that any subsequent decoration with
296 // the same id will be deemed as a duplicate. Then, at the call site, we
297 // will be able to handle duplicates in the best way.
298 unsigned Opcode = MI.getOpcode();
299 if ((Opcode == SPIRV::OpDecorate) && i >= 2) {
300 unsigned DecorationID = MI.getOperand(1).getImm();
301 if (DecorationID != SPIRV::Decoration::FuncParamAttr &&
302 DecorationID != SPIRV::Decoration::UserSemantic &&
303 DecorationID != SPIRV::Decoration::CacheControlLoadINTEL &&
304 DecorationID != SPIRV::Decoration::CacheControlStoreINTEL)
305 continue;
306 }
307 const MachineOperand &MO = MI.getOperand(i);
308 size_t h;
309 if (MO.isReg()) {
310 if (!UseDefReg && MO.isDef()) {
311 assert(!DefReg.isValid() && "Multiple def registers.");
312 DefReg = MO.getReg();
313 continue;
314 }
315 Register RegAlias = MAI.getRegisterAlias(MI.getMF(), MO.getReg());
316 if (!RegAlias.isValid()) {
317 LLVM_DEBUG({
318 dbgs() << "Unexpectedly, no global id found for the operand ";
319 MO.print(dbgs());
320 dbgs() << "\nInstruction: ";
321 MI.print(dbgs());
322 dbgs() << "\n";
323 });
324 report_fatal_error("All v-regs must have been mapped to global id's");
325 }
326 // mimic llvm::hash_value(const MachineOperand &MO)
327 h = hash_combine(MO.getType(), (unsigned)RegAlias, MO.getSubReg(),
328 MO.isDef());
329 } else {
330 h = hash_value(MO);
331 }
332 Signature.push_back(h);
333 }
334
335 if (DefReg.isValid()) {
336 // Decorations change the semantics of the current instruction. So two
337 // identical instruction with different decorations cannot be merged. That
338 // is why we add the decorations to the signature.
339 appendDecorationsForReg(MI.getMF()->getRegInfo(), DefReg, Signature);
340 }
341 return Signature;
342}
343
344// Operand index of Invoke in device enqueue instructions, 0 if none.
345static unsigned getInvokeOperandIdx(unsigned Opcode) {
346 switch (Opcode) {
347 case SPIRV::OpEnqueueKernel:
348 return 8;
349 case SPIRV::OpGetKernelNDrangeSubGroupCount:
350 case SPIRV::OpGetKernelNDrangeMaxSubGroupSize:
351 return 3;
352 case SPIRV::OpGetKernelWorkGroupSize:
353 case SPIRV::OpGetKernelPreferredWorkGroupSizeMultiple:
354 return 2;
355 default:
356 return 0;
357 }
358}
359
360bool SPIRVModuleAnalysisImpl::isDeclSection(const MachineRegisterInfo &MRI,
361 const MachineInstr &MI) {
362 unsigned Opcode = MI.getOpcode();
363 switch (Opcode) {
364 case SPIRV::OpTypeForwardPointer:
365 // omit now, collect later
366 return false;
367 case SPIRV::OpVariable:
368 case SPIRV::OpUntypedVariableKHR:
369 return static_cast<SPIRV::StorageClass::StorageClass>(
370 MI.getOperand(2).getImm()) != SPIRV::StorageClass::Function;
371 case SPIRV::OpFunction:
372 case SPIRV::OpFunctionParameter:
373 return true;
374 }
375 if (GR->hasConstFunPtr() && Opcode == SPIRV::OpUndef) {
376 // The OpUndef may be a placeholder for a function reference recorded by
377 // selectGlobalValue. Skip emitting it if any user consumes it as a
378 // function-pointer-like operand (OpConstantFunctionPointerINTEL operand 2,
379 // or the Invoke operand of a device enqueue instruction). The rewrite
380 // happens in visitFunPtrUse, which aliases the OpUndef's vreg to the
381 // function's global <id>.
382 Register DefReg = MI.getOperand(0).getReg();
383 if (GR->getFunctionDefinitionByUse(&MI.getOperand(0))) {
384 for (MachineInstr &UseMI : MRI.use_instructions(DefReg)) {
385 unsigned UseOp = UseMI.getOpcode();
386 if (UseOp == SPIRV::OpConstantFunctionPointerINTEL ||
387 getInvokeOperandIdx(UseOp)) {
388 MAI.setSkipEmission(&MI);
389 return false;
390 }
391 }
392 }
393 for (MachineInstr &UseMI : MRI.use_instructions(DefReg)) {
394 if (UseMI.getOpcode() != SPIRV::OpConstantFunctionPointerINTEL)
395 continue;
396 // it's a dummy definition, FP constant refers to a function,
397 // and this is resolved in another way; let's skip this definition
398 assert(UseMI.getOperand(2).isReg() &&
399 UseMI.getOperand(2).getReg() == DefReg);
400 MAI.setSkipEmission(&MI);
401 return false;
402 }
403 }
404 return TII->isTypeDeclInstr(MI) || TII->isConstantInstr(MI) ||
405 TII->isInlineAsmDefInstr(MI);
406}
407
408// This is a special case of a function pointer referring to a possibly
409// forward function declaration. The operand is a dummy OpUndef that
410// requires a special treatment.
411// FunPtrOp is the MachineOperand previously recorded via
412// SPIRVGlobalRegistry::recordFunctionPointer, identifying which Function
413// this placeholder refers to.
414void SPIRVModuleAnalysisImpl::visitFunPtrUse(
415 Register OpReg, const MachineOperand *FunPtrOp,
416 InstrGRegsMap &SignatureToGReg,
417 std::map<const Value *, unsigned> &GlobalToGReg,
418 const MachineFunction *MF) {
419 const MachineOperand *OpFunDef = GR->getFunctionDefinitionByUse(FunPtrOp);
420 assert(OpFunDef && OpFunDef->isReg());
421 // find the actual function definition and number it globally in advance
422 const MachineInstr *OpDefMI = OpFunDef->getParent();
423 assert(OpDefMI && OpDefMI->getOpcode() == SPIRV::OpFunction);
424 const MachineFunction *FunDefMF = OpDefMI->getParent()->getParent();
425 const MachineRegisterInfo &FunDefMRI = FunDefMF->getRegInfo();
426 do {
427 visitDecl(FunDefMRI, SignatureToGReg, GlobalToGReg, FunDefMF, *OpDefMI);
428 OpDefMI = OpDefMI->getNextNode();
429 } while (OpDefMI && (OpDefMI->getOpcode() == SPIRV::OpFunction ||
430 OpDefMI->getOpcode() == SPIRV::OpFunctionParameter));
431 // associate the function pointer with the newly assigned global number
432 MCRegister GlobalFunDefReg =
433 MAI.getRegisterAlias(FunDefMF, OpFunDef->getReg());
434 assert(GlobalFunDefReg.isValid() &&
435 "Function definition must refer to a global register");
436 MAI.setRegisterAlias(MF, OpReg, GlobalFunDefReg);
437}
438
439// Depth first recursive traversal of dependencies. Repeated visits are guarded
440// by MAI.hasRegisterAlias().
441void SPIRVModuleAnalysisImpl::visitDecl(
442 const MachineRegisterInfo &MRI, InstrGRegsMap &SignatureToGReg,
443 std::map<const Value *, unsigned> &GlobalToGReg, const MachineFunction *MF,
444 const MachineInstr &MI) {
445 unsigned Opcode = MI.getOpcode();
446
447 // Process each operand of the instruction to resolve dependencies
448 for (const MachineOperand &MO : MI.operands()) {
449 if (!MO.isReg() || MO.isDef())
450 continue;
451 Register OpReg = MO.getReg();
452 // Handle function pointers special case
453 if (Opcode == SPIRV::OpConstantFunctionPointerINTEL &&
454 MRI.getRegClass(OpReg) == &SPIRV::pIDRegClass) {
455 visitFunPtrUse(OpReg, &MI.getOperand(2), SignatureToGReg, GlobalToGReg,
456 MF);
457 continue;
458 }
459 // Skip already processed instructions
460 if (MAI.hasRegisterAlias(MF, MO.getReg()))
461 continue;
462 // Recursively visit dependencies
463 if (const MachineInstr *OpDefMI = MRI.getUniqueVRegDef(OpReg)) {
464 if (isDeclSection(MRI, *OpDefMI))
465 visitDecl(MRI, SignatureToGReg, GlobalToGReg, MF, *OpDefMI);
466 continue;
467 }
468 // Handle the unexpected case of no unique definition for the SPIR-V
469 // instruction
470 LLVM_DEBUG({
471 dbgs() << "Unexpectedly, no unique definition for the operand ";
472 MO.print(dbgs());
473 dbgs() << "\nInstruction: ";
474 MI.print(dbgs());
475 dbgs() << "\n";
476 });
478 "No unique definition is found for the virtual register");
479 }
480
481 MCRegister GReg;
482 bool IsFunDef = false;
483 if (TII->isSpecConstantInstr(MI)) {
484 GReg = MAI.getNextIDRegister();
485 MAI.MS[SPIRV::MB_TypeConstVars].push_back(&MI);
486 } else if (Opcode == SPIRV::OpFunction ||
487 Opcode == SPIRV::OpFunctionParameter) {
488 GReg = handleFunctionOrParameter(MF, MI, GlobalToGReg, IsFunDef);
489 } else if (Opcode == SPIRV::OpTypeStruct ||
490 Opcode == SPIRV::OpConstantComposite) {
491 GReg = handleTypeDeclOrConstant(MI, SignatureToGReg);
492 const MachineInstr *NextInstr = MI.getNextNode();
493 while (NextInstr &&
494 ((Opcode == SPIRV::OpTypeStruct &&
495 NextInstr->getOpcode() == SPIRV::OpTypeStructContinuedINTEL) ||
496 (Opcode == SPIRV::OpConstantComposite &&
497 NextInstr->getOpcode() ==
498 SPIRV::OpConstantCompositeContinuedINTEL))) {
499 MCRegister Tmp = handleTypeDeclOrConstant(*NextInstr, SignatureToGReg);
500 MAI.setRegisterAlias(MF, NextInstr->getOperand(0).getReg(), Tmp);
501 MAI.setSkipEmission(NextInstr);
502 NextInstr = NextInstr->getNextNode();
503 }
504 } else if (TII->isTypeDeclInstr(MI) || TII->isConstantInstr(MI) ||
505 TII->isInlineAsmDefInstr(MI)) {
506 GReg = handleTypeDeclOrConstant(MI, SignatureToGReg);
507 } else if (Opcode == SPIRV::OpVariable ||
508 Opcode == SPIRV::OpUntypedVariableKHR) {
509 GReg = handleVariable(MF, MI, GlobalToGReg);
510 } else {
511 LLVM_DEBUG({
512 dbgs() << "\nInstruction: ";
513 MI.print(dbgs());
514 dbgs() << "\n";
515 });
516 llvm_unreachable("Unexpected instruction is visited");
517 }
518 MAI.setRegisterAlias(MF, MI.getOperand(0).getReg(), GReg);
519 if (!IsFunDef)
520 MAI.setSkipEmission(&MI);
521}
522
523MCRegister SPIRVModuleAnalysisImpl::handleFunctionOrParameter(
524 const MachineFunction *MF, const MachineInstr &MI,
525 std::map<const Value *, unsigned> &GlobalToGReg, bool &IsFunDef) {
526 const Value *GObj = GR->getGlobalObject(MF, MI.getOperand(0).getReg());
527 assert(GObj && "Unregistered global definition");
528 const Function *F = dyn_cast<Function>(GObj);
529 if (!F)
530 F = dyn_cast<Argument>(GObj)->getParent();
531 assert(F && "Expected a reference to a function or an argument");
532 IsFunDef = !F->isDeclaration();
533 auto [It, Inserted] = GlobalToGReg.try_emplace(GObj);
534 if (!Inserted)
535 return It->second;
536 MCRegister GReg = MAI.getNextIDRegister();
537 It->second = GReg;
538 if (!IsFunDef)
539 MAI.MS[SPIRV::MB_ExtFuncDecls].push_back(&MI);
540 return GReg;
541}
542
543MCRegister SPIRVModuleAnalysisImpl::handleTypeDeclOrConstant(
544 const MachineInstr &MI, InstrGRegsMap &SignatureToGReg) {
545 InstrSignature MISign = instrToSignature(MI, MAI, false);
546 auto [It, Inserted] = SignatureToGReg.try_emplace(MISign);
547 if (!Inserted)
548 return It->second;
549 MCRegister GReg = MAI.getNextIDRegister();
550 It->second = GReg;
551 MAI.MS[SPIRV::MB_TypeConstVars].push_back(&MI);
552 return GReg;
553}
554
555MCRegister SPIRVModuleAnalysisImpl::handleVariable(
556 const MachineFunction *MF, const MachineInstr &MI,
557 std::map<const Value *, unsigned> &GlobalToGReg) {
558 MAI.GlobalVarList.push_back(&MI);
559 const Value *GObj = GR->getGlobalObject(MF, MI.getOperand(0).getReg());
560 assert(GObj && "Unregistered global definition");
561 auto [It, Inserted] = GlobalToGReg.try_emplace(GObj);
562 if (!Inserted)
563 return It->second;
564 MCRegister GReg = MAI.getNextIDRegister();
565 It->second = GReg;
566 MAI.MS[SPIRV::MB_TypeConstVars].push_back(&MI);
567 if (const auto *GV = dyn_cast<GlobalVariable>(GObj))
568 MAI.GlobalObjMap[GV] = GReg;
569 return GReg;
570}
571
572void SPIRVModuleAnalysisImpl::collectDeclarations(const Module &M) {
573 InstrGRegsMap SignatureToGReg;
574 std::map<const Value *, unsigned> GlobalToGReg;
575 for (const Function &F : M) {
576 MachineFunction *MF = GetMF(F);
577 if (!MF)
578 continue;
579 const MachineRegisterInfo &MRI = MF->getRegInfo();
580 unsigned PastHeader = 0;
581 for (MachineBasicBlock &MBB : *MF) {
582 for (MachineInstr &MI : MBB) {
583 if (MI.getNumOperands() == 0)
584 continue;
585 unsigned Opcode = MI.getOpcode();
586 if (Opcode == SPIRV::OpFunction) {
587 if (PastHeader == 0) {
588 PastHeader = 1;
589 continue;
590 }
591 } else if (Opcode == SPIRV::OpFunctionParameter) {
592 if (PastHeader < 2)
593 continue;
594 } else if (PastHeader > 0) {
595 PastHeader = 2;
596 }
597
598 const MachineOperand &DefMO = MI.getOperand(0);
599 switch (Opcode) {
600 case SPIRV::OpExtension:
601 MAI.Reqs.addExtension(SPIRV::Extension::Extension(DefMO.getImm()));
602 MAI.setSkipEmission(&MI);
603 break;
604 case SPIRV::OpCapability:
605 MAI.Reqs.addCapability(SPIRV::Capability::Capability(DefMO.getImm()));
606 MAI.setSkipEmission(&MI);
607 if (PastHeader > 0)
608 PastHeader = 2;
609 break;
610 default:
611 if (DefMO.isReg() && isDeclSection(MRI, MI) &&
612 !MAI.hasRegisterAlias(MF, DefMO.getReg()))
613 visitDecl(MRI, SignatureToGReg, GlobalToGReg, MF, MI);
614 // Device enqueue instructions are not decls, but their Invoke
615 // operand may be a function-pointer placeholder OpUndef. Resolve it
616 // to the OpFunction's global <id> via visitFunPtrUse.
617 if (unsigned InvokeIdx = getInvokeOperandIdx(Opcode)) {
618 const MachineOperand &InvokeMO = MI.getOperand(InvokeIdx);
619 if (InvokeMO.isReg()) {
620 Register InvokeReg = InvokeMO.getReg();
621 if (!MAI.hasRegisterAlias(MF, InvokeReg)) {
622 if (const MachineInstr *DefMI =
623 MRI.getUniqueVRegDef(InvokeReg)) {
624 if (DefMI->getOpcode() == SPIRV::OpUndef) {
625 const MachineOperand *FunPtrOp = &DefMI->getOperand(0);
626 if (GR->getFunctionDefinitionByUse(FunPtrOp))
627 visitFunPtrUse(InvokeReg, FunPtrOp, SignatureToGReg,
628 GlobalToGReg, MF);
629 }
630 }
631 }
632 }
633 }
634 }
635 }
636 }
637 }
638}
639
640// Look for IDs declared with Import linkage, and map the corresponding function
641// to the register defining that variable (which will usually be the result of
642// an OpFunction). This lets us call externally imported functions using
643// the correct ID registers.
644void SPIRVModuleAnalysisImpl::collectFuncNames(MachineInstr &MI,
645 const Function *F) {
646 if (MI.getOpcode() == SPIRV::OpDecorate) {
647 // If it's got Import linkage.
648 auto Dec = MI.getOperand(1).getImm();
649 if (Dec == SPIRV::Decoration::LinkageAttributes) {
650 auto Lnk = MI.getOperand(MI.getNumOperands() - 1).getImm();
651 if (Lnk == SPIRV::LinkageType::Import) {
652 // Map imported function name to function ID register.
653 const Function *ImportedFunc =
654 F->getParent()->getFunction(getStringImm(MI, 2));
655 Register Target = MI.getOperand(0).getReg();
656 MAI.GlobalObjMap[ImportedFunc] =
657 MAI.getRegisterAlias(MI.getMF(), Target);
658 }
659 }
660 } else if (MI.getOpcode() == SPIRV::OpFunction) {
661 // Record all internal OpFunction declarations.
662 Register Reg = MI.defs().begin()->getReg();
663 MCRegister GlobalReg = MAI.getRegisterAlias(MI.getMF(), Reg);
664 assert(GlobalReg.isValid());
665 MAI.GlobalObjMap[F] = GlobalReg;
666 }
667}
668
669// Collect the given instruction in the specified MS. We assume global register
670// numbering has already occurred by this point. We can directly compare reg
671// arguments when detecting duplicates.
674 bool Append = true) {
675 MAI.setSkipEmission(&MI);
676 InstrSignature MISign = instrToSignature(MI, MAI, true);
677 auto FoundMI = IS.insert(std::move(MISign));
678 if (!FoundMI.second) {
679 if (MI.getOpcode() == SPIRV::OpDecorate) {
680 assert(MI.getNumOperands() >= 2 &&
681 "Decoration instructions must have at least 2 operands");
682 assert(MSType == SPIRV::MB_Annotations &&
683 "Only OpDecorate instructions can be duplicates");
684 // For FPFastMathMode decoration, we need to merge the flags of the
685 // duplicate decoration with the original one, so we need to find the
686 // original instruction that has the same signature. For the rest of
687 // instructions, we will simply skip the duplicate.
688 if (MI.getOperand(1).getImm() != SPIRV::Decoration::FPFastMathMode)
689 return; // Skip duplicates of other decorations.
690
691 const SPIRV::InstrList &Decorations = MAI.MS[MSType];
692 for (const MachineInstr *OrigMI : Decorations) {
693 if (instrToSignature(*OrigMI, MAI, true) == MISign) {
694 assert(OrigMI->getNumOperands() == MI.getNumOperands() &&
695 "Original instruction must have the same number of operands");
696 assert(
697 OrigMI->getNumOperands() == 3 &&
698 "FPFastMathMode decoration must have 3 operands for OpDecorate");
699 unsigned OrigFlags = OrigMI->getOperand(2).getImm();
700 unsigned NewFlags = MI.getOperand(2).getImm();
701 if (OrigFlags == NewFlags)
702 return; // No need to merge, the flags are the same.
703
704 // Emit warning about possible conflict between flags.
705 unsigned FinalFlags = OrigFlags | NewFlags;
706 llvm::errs()
707 << "Warning: Conflicting FPFastMathMode decoration flags "
708 "in instruction: "
709 << *OrigMI << "Original flags: " << OrigFlags
710 << ", new flags: " << NewFlags
711 << ". They will be merged on a best effort basis, but not "
712 "validated. Final flags: "
713 << FinalFlags << "\n";
714 MachineInstr *OrigMINonConst = const_cast<MachineInstr *>(OrigMI);
715 MachineOperand &OrigFlagsOp = OrigMINonConst->getOperand(2);
716 OrigFlagsOp = MachineOperand::CreateImm(FinalFlags);
717 return; // Merge done, so we found a duplicate; don't add it to MAI.MS
718 }
719 }
720 assert(false && "No original instruction found for the duplicate "
721 "OpDecorate, but we found one in IS.");
722 }
723 return; // insert failed, so we found a duplicate; don't add it to MAI.MS
724 }
725 // No duplicates, so add it.
726 if (Append)
727 MAI.MS[MSType].push_back(&MI);
728 else
729 MAI.MS[MSType].insert(MAI.MS[MSType].begin(), &MI);
730}
731
732// Some global instructions make reference to function-local ID regs, so cannot
733// be correctly collected until these registers are globally numbered.
734void SPIRVModuleAnalysisImpl::processOtherInstrs(const Module &M) {
736 for (const Function &F : M) {
737 if (F.isDeclaration())
738 continue;
739 MachineFunction *MF = GetMF(F);
740 assert(MF);
741
742 for (MachineBasicBlock &MBB : *MF)
743 for (MachineInstr &MI : MBB) {
744 if (MI.isDebugValueLike()) {
745 MAI.DebugValueMIs.push_back(&MI);
746 continue;
747 }
748 if (MAI.getSkipEmission(&MI))
749 continue;
750 const unsigned OpCode = MI.getOpcode();
751 if (OpCode == SPIRV::OpString) {
753 } else if (OpCode == SPIRV::OpExtInst && MI.getOperand(2).isImm() &&
754 MI.getOperand(2).getImm() ==
755 SPIRV::InstructionSet::
756 NonSemantic_Shader_DebugInfo_100) {
757 // TODO: This branch is dead. SPIRVNonSemanticDebugHandler emits NSDI
758 // instructions directly as MCInsts at print time; no
759 // MachineInstructions with the NSDI ext set are created anymore.
760 // Remove this block and
761 // MB_NonSemanticGlobalDI once per-function NSDI emission is confirmed
762 // not to need MIR routing.
763 MachineOperand Ins = MI.getOperand(3);
764 namespace NS = SPIRV::NonSemanticExtInst;
765 static constexpr int64_t GlobalNonSemanticDITy[] = {
766 NS::DebugSource, NS::DebugCompilationUnit, NS::DebugInfoNone,
767 NS::DebugTypeBasic, NS::DebugTypePointer};
768 bool IsGlobalDI = false;
769 for (unsigned Idx = 0; Idx < std::size(GlobalNonSemanticDITy); ++Idx)
770 IsGlobalDI |= Ins.getImm() == GlobalNonSemanticDITy[Idx];
771 if (IsGlobalDI)
773 } else if (OpCode == SPIRV::OpName || OpCode == SPIRV::OpMemberName) {
775 } else if (OpCode == SPIRV::OpEntryPoint) {
777 } else if (TII->isAliasingInstr(MI)) {
779 } else if (TII->isDecorationInstr(MI)) {
780 if (MI.getOpcode() == SPIRV::OpDecorate &&
781 MI.getOperand(1).getImm() ==
782 static_cast<unsigned>(
783 SPIRV::Decoration::AuxDataInstructionMetadata)) {
784 MAI.setSkipEmission(&MI);
785 std::string Str = getStringImm(MI, 2);
787 auto MaybeKind =
788 StringSwitch<std::optional<AMDMD>>(Str)
789 .Case("amdgpu.no.fine.grained.memory",
790 AMDMD::NoFineGrainedMemory)
791 .Case("amdgpu.no.remote.memory", AMDMD::NoRemoteMemory)
792 .Case("atomic.ignore.denormal.mode",
793 AMDMD::IgnoreDenormalMode)
794 .Default(std::nullopt);
795 if (MaybeKind)
796 MAI.InstrAuxDataRecords.push_back(
797 {MF, MI.getOperand(0).getReg(), *MaybeKind});
798 continue;
799 }
801 collectFuncNames(MI, &F);
802 } else if (TII->isConstantInstr(MI)) {
803 // Now OpSpecConstant*s are not in DT,
804 // but they need to be collected anyway.
806 } else if (OpCode == SPIRV::OpFunction) {
807 collectFuncNames(MI, &F);
808 } else if (OpCode == SPIRV::OpTypeForwardPointer) {
810 }
811 }
812 }
813 // Selection order can place a scope/list ahead of a domain/scope it
814 // references. The dependency meanwhile is domain -> scope -> list, so sort
815 // the def before its uses.
816 auto AliasingTier = [](const MachineInstr *MI) {
817 switch (MI->getOpcode()) {
818 case SPIRV::OpAliasDomainDeclINTEL:
819 return 0;
820 case SPIRV::OpAliasScopeDeclINTEL:
821 return 1;
822 case SPIRV::OpAliasScopeListDeclINTEL:
823 return 2;
824 default:
825 llvm_unreachable("unexpected aliasing instruction");
826 }
827 };
829 [&](const MachineInstr *LHS, const MachineInstr *RHS) {
830 return AliasingTier(LHS) < AliasingTier(RHS);
831 });
832}
833
834// Number registers in all functions globally from 0 onwards and store
835// the result in global register alias table. Some registers are already
836// numbered.
837void SPIRVModuleAnalysisImpl::numberRegistersGlobally(const Module &M) {
838 for (const Function &F : M) {
839 if (F.isDeclaration())
840 continue;
841 MachineFunction *MF = GetMF(F);
842 assert(MF);
843 for (MachineBasicBlock &MBB : *MF) {
844 for (MachineInstr &MI : MBB) {
845 for (MachineOperand &Op : MI.operands()) {
846 if (!Op.isReg())
847 continue;
848 Register Reg = Op.getReg();
849 if (MAI.hasRegisterAlias(MF, Reg))
850 continue;
851 MCRegister NewReg = MAI.getNextIDRegister();
852 MAI.setRegisterAlias(MF, Reg, NewReg);
853 }
854 if (MI.getOpcode() != SPIRV::OpExtInst)
855 continue;
856 auto Set = MI.getOperand(2).getImm();
857 auto [It, Inserted] = MAI.ExtInstSetMap.try_emplace(Set);
858 if (Inserted)
859 It->second = MAI.getNextIDRegister();
860 }
861 }
862 }
863}
864
865// RequirementHandler implementations.
867 SPIRV::OperandCategory::OperandCategory Category, uint32_t i,
868 const SPIRVSubtarget &ST) {
869 addRequirements(getSymbolicOperandRequirements(Category, i, ST, *this));
870}
871
872void SPIRV::RequirementHandler::recursiveAddCapabilities(
873 const CapabilityList &ToPrune) {
874 for (const auto &Cap : ToPrune) {
875 AllCaps.insert(Cap);
876 CapabilityList ImplicitDecls =
877 getSymbolicOperandCapabilities(OperandCategory::CapabilityOperand, Cap);
878 recursiveAddCapabilities(ImplicitDecls);
879 }
880}
881
883 for (const auto &Cap : ToAdd) {
884 bool IsNewlyInserted = AllCaps.insert(Cap).second;
885 if (!IsNewlyInserted) // Don't re-add if it's already been declared.
886 continue;
887 CapabilityList ImplicitDecls =
888 getSymbolicOperandCapabilities(OperandCategory::CapabilityOperand, Cap);
889 recursiveAddCapabilities(ImplicitDecls);
890 MinimalCaps.push_back(Cap);
891 }
892}
893
895 const SPIRV::Requirements &Req) {
896 if (!Req.IsSatisfiable)
897 report_fatal_error("Adding SPIR-V requirements this target can't satisfy.");
898
899 if (Req.Cap.has_value())
900 addCapabilities({Req.Cap.value()});
901
902 addExtensions(Req.Exts);
903
904 if (!Req.MinVer.empty()) {
905 if (!MaxVersion.empty() && Req.MinVer > MaxVersion) {
906 LLVM_DEBUG(dbgs() << "Conflicting version requirements: >= " << Req.MinVer
907 << " and <= " << MaxVersion << "\n");
908 report_fatal_error("Adding SPIR-V requirements that can't be satisfied.");
909 }
910
911 if (MinVersion.empty() || Req.MinVer > MinVersion)
912 MinVersion = Req.MinVer;
913 }
914
915 if (!Req.MaxVer.empty()) {
916 if (!MinVersion.empty() && Req.MaxVer < MinVersion) {
917 LLVM_DEBUG(dbgs() << "Conflicting version requirements: <= " << Req.MaxVer
918 << " and >= " << MinVersion << "\n");
919 report_fatal_error("Adding SPIR-V requirements that can't be satisfied.");
920 }
921
922 if (MaxVersion.empty() || Req.MaxVer < MaxVersion)
923 MaxVersion = Req.MaxVer;
924 }
925}
926
928 const SPIRVSubtarget &ST) const {
929 // Report as many errors as possible before aborting the compilation.
930 bool IsSatisfiable = true;
931 auto TargetVer = ST.getSPIRVVersion();
932
933 if (!MaxVersion.empty() && !TargetVer.empty() && MaxVersion < TargetVer) {
935 dbgs() << "Target SPIR-V version too high for required features\n"
936 << "Required max version: " << MaxVersion << " target version "
937 << TargetVer << "\n");
938 IsSatisfiable = false;
939 }
940
941 if (!MinVersion.empty() && !TargetVer.empty() && MinVersion > TargetVer) {
942 LLVM_DEBUG(dbgs() << "Target SPIR-V version too low for required features\n"
943 << "Required min version: " << MinVersion
944 << " target version " << TargetVer << "\n");
945 IsSatisfiable = false;
946 }
947
948 if (!MinVersion.empty() && !MaxVersion.empty() && MinVersion > MaxVersion) {
950 dbgs()
951 << "Version is too low for some features and too high for others.\n"
952 << "Required SPIR-V min version: " << MinVersion
953 << " required SPIR-V max version " << MaxVersion << "\n");
954 IsSatisfiable = false;
955 }
956
957 AvoidCapabilitiesSet AvoidCaps;
958 if (!ST.isShader())
959 AvoidCaps.S.insert(SPIRV::Capability::Shader);
960 else
961 AvoidCaps.S.insert(SPIRV::Capability::Kernel);
962
963 for (auto Cap : MinimalCaps) {
964 if (AvailableCaps.contains(Cap) && !AvoidCaps.S.contains(Cap))
965 continue;
966 LLVM_DEBUG(dbgs() << "Capability not supported: "
968 OperandCategory::CapabilityOperand, Cap)
969 << "\n");
970 IsSatisfiable = false;
971 }
972
973 for (auto Ext : AllExtensions) {
974 if (ST.canUseExtension(Ext))
975 continue;
976 LLVM_DEBUG(dbgs() << "Extension not supported: "
978 OperandCategory::ExtensionOperand, Ext)
979 << "\n");
980 IsSatisfiable = false;
981 }
982
983 if (!IsSatisfiable)
984 report_fatal_error("Unable to meet SPIR-V requirements for this target.");
985}
986
987// Add the given capabilities and all their implicitly defined capabilities too.
989 for (const auto Cap : ToAdd)
990 if (AvailableCaps.insert(Cap).second)
992 SPIRV::OperandCategory::CapabilityOperand, Cap));
993}
994
996 const Capability::Capability ToRemove,
997 const Capability::Capability IfPresent) {
998 if (AllCaps.contains(IfPresent)) {
999 AllCaps.erase(ToRemove);
1000 llvm::erase(MinimalCaps, ToRemove);
1001 }
1002}
1003
1004namespace llvm {
1005namespace SPIRV {
1007 // Provided by both all supported Vulkan versions and OpenCl.
1008 addAvailableCaps({Capability::Shader, Capability::Linkage, Capability::Int8,
1009 Capability::Int16});
1010
1011 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 3)))
1012 addAvailableCaps({Capability::GroupNonUniform,
1013 Capability::GroupNonUniformVote,
1014 Capability::GroupNonUniformArithmetic,
1015 Capability::GroupNonUniformBallot,
1016 Capability::GroupNonUniformClustered,
1017 Capability::GroupNonUniformShuffle,
1018 Capability::GroupNonUniformShuffleRelative,
1019 Capability::GroupNonUniformQuad});
1020
1021 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 6)))
1022 addAvailableCaps({Capability::DotProduct, Capability::DotProductInputAll,
1023 Capability::DotProductInput4x8Bit,
1024 Capability::DotProductInput4x8BitPacked,
1025 Capability::DemoteToHelperInvocation});
1026
1027 // Add capabilities enabled by extensions.
1028 for (auto Extension : ST.getAllAvailableExtensions()) {
1029 CapabilityList EnabledCapabilities =
1031 addAvailableCaps(EnabledCapabilities);
1032 }
1033
1034 // EXT and NV use the same capability.
1035 if (ST.canUseExtension(Extension::SPV_EXT_shader_subgroup_partitioned))
1036 addAvailableCaps({Capability::GroupNonUniformPartitionedNV});
1037
1038 if (!ST.isShader()) {
1039 initAvailableCapabilitiesForOpenCL(ST);
1040 return;
1041 }
1042
1043 if (ST.isShader()) {
1044 initAvailableCapabilitiesForVulkan(ST);
1045 return;
1046 }
1047
1048 report_fatal_error("Unimplemented environment for SPIR-V generation.");
1049}
1050
1051void RequirementHandler::initAvailableCapabilitiesForOpenCL(
1052 const SPIRVSubtarget &ST) {
1053 // Add the min requirements for different OpenCL and SPIR-V versions.
1054 addAvailableCaps({Capability::Addresses, Capability::Float16Buffer,
1055 Capability::Kernel, Capability::Vector16,
1056 Capability::Groups, Capability::GenericPointer,
1057 Capability::StorageImageWriteWithoutFormat,
1058 Capability::StorageImageReadWithoutFormat});
1059 if (ST.hasOpenCLFullProfile())
1060 addAvailableCaps({Capability::Int64, Capability::Int64Atomics});
1061 if (ST.hasOpenCLImageSupport()) {
1062 addAvailableCaps({Capability::ImageBasic, Capability::LiteralSampler,
1063 Capability::Image1D, Capability::SampledBuffer,
1064 Capability::ImageBuffer});
1065 if (ST.isAtLeastOpenCLVer(VersionTuple(2, 0)))
1066 addAvailableCaps({Capability::ImageReadWrite});
1067 }
1068 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 1)) &&
1069 ST.isAtLeastOpenCLVer(VersionTuple(2, 2)))
1070 addAvailableCaps({Capability::SubgroupDispatch, Capability::PipeStorage});
1071 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 4)))
1072 addAvailableCaps({Capability::DenormPreserve, Capability::DenormFlushToZero,
1073 Capability::SignedZeroInfNanPreserve,
1074 Capability::RoundingModeRTE,
1075 Capability::RoundingModeRTZ});
1076 // TODO: verify if this needs some checks.
1077 addAvailableCaps({Capability::Float16, Capability::Float64});
1078
1079 // TODO: add OpenCL extensions.
1080}
1081
1082void RequirementHandler::initAvailableCapabilitiesForVulkan(
1083 const SPIRVSubtarget &ST) {
1084
1085 // Core in Vulkan 1.1 and earlier.
1086 addAvailableCaps({Capability::Int64,
1087 Capability::Geometry,
1088 Capability::Float16,
1089 Capability::Float64,
1090 Capability::GroupNonUniform,
1091 Capability::Image1D,
1092 Capability::SampledBuffer,
1093 Capability::ImageBuffer,
1094 Capability::UniformBufferArrayDynamicIndexing,
1095 Capability::SampledImageArrayDynamicIndexing,
1096 Capability::StorageBufferArrayDynamicIndexing,
1097 Capability::StorageImageArrayDynamicIndexing,
1098 Capability::DerivativeControl,
1099 Capability::SampleRateShading,
1100 Capability::MinLod,
1101 Capability::ImageQuery,
1102 Capability::ImageGatherExtended,
1103 Capability::Addresses,
1104 Capability::VulkanMemoryModelKHR,
1105 Capability::StorageImageExtendedFormats,
1106 Capability::StorageImageMultisample,
1107 Capability::ImageMSArray});
1108
1109 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 3)) ||
1110 ST.canUseExtension(Extension::SPV_KHR_variable_pointers))
1111 addAvailableCaps({Capability::VariablePointersStorageBuffer,
1112 Capability::VariablePointers});
1113
1114 // Became core in Vulkan 1.1.
1115 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 3)))
1116 addAvailableCaps({Capability::DrawParameters, Capability::MultiView});
1117
1118 // Became core in Vulkan 1.2
1119 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 5))) {
1121 {Capability::Int64Atomics, Capability::ShaderNonUniformEXT,
1122 Capability::RuntimeDescriptorArrayEXT,
1123 Capability::InputAttachmentArrayDynamicIndexingEXT,
1124 Capability::UniformTexelBufferArrayDynamicIndexingEXT,
1125 Capability::StorageTexelBufferArrayDynamicIndexingEXT,
1126 Capability::UniformBufferArrayNonUniformIndexingEXT,
1127 Capability::SampledImageArrayNonUniformIndexingEXT,
1128 Capability::StorageBufferArrayNonUniformIndexingEXT,
1129 Capability::StorageImageArrayNonUniformIndexingEXT,
1130 Capability::InputAttachmentArrayNonUniformIndexingEXT,
1131 Capability::UniformTexelBufferArrayNonUniformIndexingEXT,
1132 Capability::StorageTexelBufferArrayNonUniformIndexingEXT});
1133 }
1134
1135 // Became core in Vulkan 1.3
1136 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 6)))
1137 addAvailableCaps({Capability::StorageImageWriteWithoutFormat,
1138 Capability::StorageImageReadWithoutFormat});
1139}
1140
1141} // namespace SPIRV
1142} // namespace llvm
1143
1144// Add a capability that became core in SPIR-V 1.3. Earlier versions require
1145// the extension that introduced it.
1147 const SPIRVSubtarget &ST,
1148 SPIRV::Capability::Capability Cap,
1149 SPIRV::Extension::Extension Ext) {
1150 Reqs.addCapability(Cap);
1151 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 3)))
1152 return;
1153 if (!ST.canUseExtension(Ext))
1155 Twine("capability ") +
1157 SPIRV::OperandCategory::CapabilityOperand, Cap) +
1158 " requires SPIR-V 1.3 or the following SPIR-V extension: " +
1159 getSymbolicOperandMnemonic(SPIRV::OperandCategory::ExtensionOperand,
1160 Ext),
1161 false);
1162 Reqs.addExtension(Ext);
1163}
1164
1165// Add the required capabilities from a decoration instruction (including
1166// BuiltIns).
1167static void addOpDecorateReqs(const MachineInstr &MI, unsigned DecIndex,
1169 const SPIRVSubtarget &ST) {
1170 int64_t DecOp = MI.getOperand(DecIndex).getImm();
1171 auto Dec = static_cast<SPIRV::Decoration::Decoration>(DecOp);
1173 SPIRV::OperandCategory::DecorationOperand, Dec, ST, Reqs));
1174
1175 if (Dec == SPIRV::Decoration::BuiltIn) {
1176 int64_t BuiltInOp = MI.getOperand(DecIndex + 1).getImm();
1177 auto BuiltIn = static_cast<SPIRV::BuiltIn::BuiltIn>(BuiltInOp);
1178 if ((BuiltIn == SPIRV::BuiltIn::BaryCoordKHR ||
1179 BuiltIn == SPIRV::BuiltIn::BaryCoordNoPerspKHR) &&
1180 !ST.canUseExtension(
1181 SPIRV::Extension::SPV_KHR_fragment_shader_barycentric))
1183 "Barycentric built-ins require the following SPIR-V extension: "
1184 "SPV_KHR_fragment_shader_barycentric",
1185 false);
1186 switch (BuiltIn) {
1187 case SPIRV::BuiltIn::BaseVertex:
1188 case SPIRV::BuiltIn::BaseInstance:
1190 Reqs, ST, SPIRV::Capability::DrawParameters,
1191 SPIRV::Extension::SPV_KHR_shader_draw_parameters);
1192 break;
1193 case SPIRV::BuiltIn::ViewIndex:
1194 addCoreInSPIRV13Capability(Reqs, ST, SPIRV::Capability::MultiView,
1195 SPIRV::Extension::SPV_KHR_multiview);
1196 break;
1197 default:
1199 SPIRV::OperandCategory::BuiltInOperand, BuiltIn, ST, Reqs));
1200 break;
1201 }
1202 } else if (Dec == SPIRV::Decoration::LinkageAttributes) {
1203 int64_t LinkageOp = MI.getOperand(MI.getNumOperands() - 1).getImm();
1204 SPIRV::LinkageType::LinkageType LnkType =
1205 static_cast<SPIRV::LinkageType::LinkageType>(LinkageOp);
1206 if (LnkType == SPIRV::LinkageType::LinkOnceODR)
1207 Reqs.addExtension(SPIRV::Extension::SPV_KHR_linkonce_odr);
1208 else if (LnkType == SPIRV::LinkageType::WeakAMD) {
1209 Reqs.addExtension(SPIRV::Extension::SPV_AMD_weak_linkage);
1210 Reqs.addCapability(SPIRV::Capability::WeakLinkageAMD);
1211 }
1212 } else if (Dec == SPIRV::Decoration::CacheControlLoadINTEL ||
1213 Dec == SPIRV::Decoration::CacheControlStoreINTEL) {
1214 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_cache_controls);
1215 } else if (Dec == SPIRV::Decoration::HostAccessINTEL) {
1216 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_global_variable_host_access);
1217 } else if (Dec == SPIRV::Decoration::InitModeINTEL ||
1218 Dec == SPIRV::Decoration::ImplementInRegisterMapINTEL) {
1219 Reqs.addExtension(
1220 SPIRV::Extension::SPV_INTEL_global_variable_fpga_decorations);
1221 } else if (Dec == SPIRV::Decoration::NonUniformEXT) {
1222 Reqs.addRequirements(SPIRV::Capability::ShaderNonUniformEXT);
1223 } else if (Dec == SPIRV::Decoration::FPMaxErrorDecorationINTEL) {
1224 Reqs.addRequirements(SPIRV::Capability::FPMaxErrorINTEL);
1225 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_fp_max_error);
1226 } else if (Dec == SPIRV::Decoration::FPFastMathMode) {
1227 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2)) {
1228 Reqs.addRequirements(SPIRV::Capability::FloatControls2);
1229 Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls2);
1230 }
1231 }
1232}
1233
1234// Add requirements for image handling.
1237 const SPIRVSubtarget &ST) {
1238 assert(MI.getNumOperands() >= 8 && "Insufficient operands for OpTypeImage");
1239 // The operand indices used here are based on the OpTypeImage layout, which
1240 // the MachineInstr follows as well.
1241 int64_t ImgFormatOp = MI.getOperand(7).getImm();
1242 auto ImgFormat = static_cast<SPIRV::ImageFormat::ImageFormat>(ImgFormatOp);
1243 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ImageFormatOperand,
1244 ImgFormat, ST);
1245
1246 bool IsArrayed = MI.getOperand(4).getImm() == 1;
1247 bool IsMultisampled = MI.getOperand(5).getImm() == 1;
1248 bool NoSampler = MI.getOperand(6).getImm() == 2;
1249 // Add dimension requirements.
1250 assert(MI.getOperand(2).isImm());
1251 switch (MI.getOperand(2).getImm()) {
1252 case SPIRV::Dim::DIM_1D:
1253 Reqs.addRequirements(NoSampler ? SPIRV::Capability::Image1D
1254 : SPIRV::Capability::Sampled1D);
1255 break;
1256 case SPIRV::Dim::DIM_2D:
1257 if (IsMultisampled && NoSampler)
1258 Reqs.addRequirements(SPIRV::Capability::StorageImageMultisample);
1259 if (IsMultisampled && IsArrayed)
1260 Reqs.addRequirements(SPIRV::Capability::ImageMSArray);
1261 break;
1262 case SPIRV::Dim::DIM_3D:
1263 break;
1264 case SPIRV::Dim::DIM_Cube:
1265 Reqs.addRequirements(SPIRV::Capability::Shader);
1266 if (IsArrayed)
1267 Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageCubeArray
1268 : SPIRV::Capability::SampledCubeArray);
1269 break;
1270 case SPIRV::Dim::DIM_Rect:
1271 Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageRect
1272 : SPIRV::Capability::SampledRect);
1273 break;
1274 case SPIRV::Dim::DIM_Buffer:
1275 Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageBuffer
1276 : SPIRV::Capability::SampledBuffer);
1277 break;
1278 case SPIRV::Dim::DIM_SubpassData:
1279 Reqs.addRequirements(SPIRV::Capability::InputAttachment);
1280 break;
1281 }
1282
1283 // Has optional access qualifier.
1284 if (!ST.isShader()) {
1285 if (MI.getNumOperands() > 8 &&
1286 MI.getOperand(8).getImm() == SPIRV::AccessQualifier::ReadWrite)
1287 Reqs.addRequirements(SPIRV::Capability::ImageReadWrite);
1288 else
1289 Reqs.addRequirements(SPIRV::Capability::ImageBasic);
1290 }
1291}
1292
1293static bool isBFloat16Type(SPIRVTypeInst TypeDef) {
1294 return TypeDef && TypeDef->getNumOperands() == 3 &&
1295 TypeDef->getOpcode() == SPIRV::OpTypeFloat &&
1296 TypeDef->getOperand(1).getImm() == 16 &&
1297 TypeDef->getOperand(2).getImm() == SPIRV::FPEncoding::BFloat16KHR;
1298}
1299
1300// Registers created after isel (e.g. by MachineCSE) may lack registry entries.
1301// Fall back to the defining instruction's result type.
1303 const SPIRVGlobalRegistry *GR) {
1304 if (SPIRVTypeInst Ty = GR->getSPIRVTypeForVReg(Reg, &MF))
1305 return Ty;
1306 const MachineRegisterInfo &MRI = MF.getRegInfo();
1307 return MRI.getVRegDef(MRI.getVRegDef(Reg)->getOperand(1).getReg());
1308}
1309
1310// Add requirements for handling atomic float instructions
1311#define ATOM_FLT_REQ_EXT_MSG(ExtName) \
1312 "The atomic float instruction requires the following SPIR-V " \
1313 "extension: SPV_EXT_shader_atomic_float" ExtName
1316 const SPIRVSubtarget &ST) {
1317 SPIRVTypeInst VecTypeDef =
1318 MI.getMF()->getRegInfo().getVRegDef(MI.getOperand(1).getReg());
1319
1320 const unsigned Rank = VecTypeDef->getOperand(2).getImm();
1321 if (Rank != 2 && Rank != 4)
1322 reportFatalUsageError("Result type of an atomic vector float instruction "
1323 "must be a 2-component or 4 component vector");
1324
1325 SPIRVTypeInst EltTypeDef =
1326 MI.getMF()->getRegInfo().getVRegDef(VecTypeDef->getOperand(1).getReg());
1327
1328 if (EltTypeDef->getOpcode() != SPIRV::OpTypeFloat ||
1329 EltTypeDef->getOperand(1).getImm() != 16)
1331 "The element type for the result type of an atomic vector float "
1332 "instruction must be a 16-bit floating-point scalar");
1333
1334 // The extension is defined for fp16, but the AMD target lets a bf16 vector
1335 // use the same instruction so it can lower to a packed bf16 atomic.
1336 if (isBFloat16Type(EltTypeDef) &&
1337 ST.getTargetTriple().getVendor() != Triple::AMD)
1339 "The element type for the result type of an atomic vector float "
1340 "instruction cannot be a bfloat16 scalar");
1341 if (!ST.canUseExtension(SPIRV::Extension::SPV_NV_shader_atomic_fp16_vector))
1343 "The atomic float16 vector instruction requires the following SPIR-V "
1344 "extension: SPV_NV_shader_atomic_fp16_vector");
1345
1346 Reqs.addExtension(SPIRV::Extension::SPV_NV_shader_atomic_fp16_vector);
1347 Reqs.addCapability(SPIRV::Capability::AtomicFloat16VectorNV);
1348}
1349
1352 const SPIRVSubtarget &ST) {
1353 assert(MI.getOperand(1).isReg() &&
1354 "Expect register operand in atomic float instruction");
1355 Register TypeReg = MI.getOperand(1).getReg();
1356 SPIRVTypeInst TypeDef = MI.getMF()->getRegInfo().getVRegDef(TypeReg);
1357
1358 if (isVectorType(TypeDef))
1359 return AddAtomicVectorFloatRequirements(MI, Reqs, ST);
1360
1361 if (TypeDef->getOpcode() != SPIRV::OpTypeFloat)
1362 report_fatal_error("Result type of an atomic float instruction must be a "
1363 "floating-point type scalar");
1364
1365 unsigned BitWidth = TypeDef->getOperand(1).getImm();
1366 unsigned Op = MI.getOpcode();
1367 if (Op == SPIRV::OpAtomicFAddEXT) {
1368 if (!ST.canUseExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_add))
1370 Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_add);
1371 switch (BitWidth) {
1372 case 16:
1373 if (isBFloat16Type(TypeDef)) {
1374 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics))
1376 "The atomic bfloat16 instruction requires the following SPIR-V "
1377 "extension: SPV_INTEL_16bit_atomics",
1378 false);
1379 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics);
1380 Reqs.addCapability(SPIRV::Capability::AtomicBFloat16AddINTEL);
1381 } else {
1382 if (!ST.canUseExtension(
1383 SPIRV::Extension::SPV_EXT_shader_atomic_float16_add))
1384 report_fatal_error(ATOM_FLT_REQ_EXT_MSG("16_add"), false);
1385 Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float16_add);
1386 Reqs.addCapability(SPIRV::Capability::AtomicFloat16AddEXT);
1387 }
1388 break;
1389 case 32:
1390 Reqs.addCapability(SPIRV::Capability::AtomicFloat32AddEXT);
1391 break;
1392 case 64:
1393 Reqs.addCapability(SPIRV::Capability::AtomicFloat64AddEXT);
1394 break;
1395 default:
1397 "Unexpected floating-point type width in atomic float instruction");
1398 }
1399 } else {
1400 if (!ST.canUseExtension(
1401 SPIRV::Extension::SPV_EXT_shader_atomic_float_min_max))
1402 report_fatal_error(ATOM_FLT_REQ_EXT_MSG("_min_max"), false);
1403 Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_min_max);
1404 switch (BitWidth) {
1405 case 16:
1406 if (isBFloat16Type(TypeDef)) {
1407 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics))
1409 "The atomic bfloat16 instruction requires the following SPIR-V "
1410 "extension: SPV_INTEL_16bit_atomics",
1411 false);
1412 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics);
1413 Reqs.addCapability(SPIRV::Capability::AtomicBFloat16MinMaxINTEL);
1414 } else {
1415 Reqs.addCapability(SPIRV::Capability::AtomicFloat16MinMaxEXT);
1416 }
1417 break;
1418 case 32:
1419 Reqs.addCapability(SPIRV::Capability::AtomicFloat32MinMaxEXT);
1420 break;
1421 case 64:
1422 Reqs.addCapability(SPIRV::Capability::AtomicFloat64MinMaxEXT);
1423 break;
1424 default:
1426 "Unexpected floating-point type width in atomic float instruction");
1427 }
1428 }
1429}
1430
1432 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1433 return false;
1434 uint32_t Dim = ImageInst->getOperand(2).getImm();
1435 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1436 return Dim == SPIRV::Dim::DIM_Buffer && Sampled == 1;
1437}
1438
1440 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1441 return false;
1442 uint32_t Dim = ImageInst->getOperand(2).getImm();
1443 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1444 return Dim == SPIRV::Dim::DIM_Buffer && Sampled == 2;
1445}
1446
1448 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1449 return false;
1450 uint32_t Dim = ImageInst->getOperand(2).getImm();
1451 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1452 return Dim != SPIRV::Dim::DIM_Buffer && Sampled == 1;
1453}
1454
1456 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1457 return false;
1458 uint32_t Dim = ImageInst->getOperand(2).getImm();
1459 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1460 return Dim == SPIRV::Dim::DIM_SubpassData && Sampled == 2;
1461}
1462
1464 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1465 return false;
1466 uint32_t Dim = ImageInst->getOperand(2).getImm();
1467 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1468 return Dim != SPIRV::Dim::DIM_Buffer && Sampled == 2;
1469}
1470
1471bool isCombinedImageSampler(MachineInstr *SampledImageInst) {
1472 if (SampledImageInst->getOpcode() != SPIRV::OpTypeSampledImage)
1473 return false;
1474
1475 const MachineRegisterInfo &MRI = SampledImageInst->getMF()->getRegInfo();
1476 Register ImageReg = SampledImageInst->getOperand(1).getReg();
1477 auto *ImageInst = MRI.getUniqueVRegDef(ImageReg);
1478 return isSampledImage(ImageInst);
1479}
1480
1482 for (const auto &MI : MRI.reg_instructions(Reg)) {
1483 if (MI.getOpcode() != SPIRV::OpDecorate)
1484 continue;
1485
1486 uint32_t Dec = MI.getOperand(1).getImm();
1487 if (Dec == SPIRV::Decoration::NonUniformEXT)
1488 return true;
1489 }
1490 return false;
1491}
1492
1495 const SPIRVSubtarget &Subtarget) {
1496 const MachineRegisterInfo &MRI = Instr.getMF()->getRegInfo();
1497 // Get the result type. If it is an image type, then the shader uses
1498 // descriptor indexing. The appropriate capabilities will be added based
1499 // on the specifics of the image.
1500 Register ResTypeReg = Instr.getOperand(1).getReg();
1501 MachineInstr *ResTypeInst = MRI.getUniqueVRegDef(ResTypeReg);
1502
1503 assert(ResTypeInst->getOpcode() == SPIRV::OpTypePointer);
1504 uint32_t StorageClass = ResTypeInst->getOperand(1).getImm();
1505 if (StorageClass != SPIRV::StorageClass::StorageClass::UniformConstant &&
1506 StorageClass != SPIRV::StorageClass::StorageClass::Uniform &&
1507 StorageClass != SPIRV::StorageClass::StorageClass::StorageBuffer) {
1508 return;
1509 }
1510
1511 bool IsNonUniform =
1512 hasNonUniformDecoration(Instr.getOperand(0).getReg(), MRI);
1513
1514 auto FirstIndexReg = Instr.getOperand(3).getReg();
1515 bool FirstIndexIsConstant =
1516 Subtarget.getInstrInfo()->isConstantInstr(*MRI.getVRegDef(FirstIndexReg));
1517
1518 if (StorageClass == SPIRV::StorageClass::StorageClass::StorageBuffer) {
1519 if (IsNonUniform)
1520 Handler.addRequirements(
1521 SPIRV::Capability::StorageBufferArrayNonUniformIndexingEXT);
1522 else if (!FirstIndexIsConstant)
1523 Handler.addRequirements(
1524 SPIRV::Capability::StorageBufferArrayDynamicIndexing);
1525 return;
1526 }
1527
1528 Register PointeeTypeReg = ResTypeInst->getOperand(2).getReg();
1529 MachineInstr *PointeeType = MRI.getUniqueVRegDef(PointeeTypeReg);
1530 if (PointeeType->getOpcode() != SPIRV::OpTypeImage &&
1531 PointeeType->getOpcode() != SPIRV::OpTypeSampledImage &&
1532 PointeeType->getOpcode() != SPIRV::OpTypeSampler) {
1533 return;
1534 }
1535
1536 if (isUniformTexelBuffer(PointeeType)) {
1537 if (IsNonUniform)
1538 Handler.addRequirements(
1539 SPIRV::Capability::UniformTexelBufferArrayNonUniformIndexingEXT);
1540 else if (!FirstIndexIsConstant)
1541 Handler.addRequirements(
1542 SPIRV::Capability::UniformTexelBufferArrayDynamicIndexingEXT);
1543 } else if (isInputAttachment(PointeeType)) {
1544 if (IsNonUniform)
1545 Handler.addRequirements(
1546 SPIRV::Capability::InputAttachmentArrayNonUniformIndexingEXT);
1547 else if (!FirstIndexIsConstant)
1548 Handler.addRequirements(
1549 SPIRV::Capability::InputAttachmentArrayDynamicIndexingEXT);
1550 } else if (isStorageTexelBuffer(PointeeType)) {
1551 if (IsNonUniform)
1552 Handler.addRequirements(
1553 SPIRV::Capability::StorageTexelBufferArrayNonUniformIndexingEXT);
1554 else if (!FirstIndexIsConstant)
1555 Handler.addRequirements(
1556 SPIRV::Capability::StorageTexelBufferArrayDynamicIndexingEXT);
1557 } else if (isSampledImage(PointeeType) ||
1558 isCombinedImageSampler(PointeeType) ||
1559 PointeeType->getOpcode() == SPIRV::OpTypeSampler) {
1560 if (IsNonUniform)
1561 Handler.addRequirements(
1562 SPIRV::Capability::SampledImageArrayNonUniformIndexingEXT);
1563 else if (!FirstIndexIsConstant)
1564 Handler.addRequirements(
1565 SPIRV::Capability::SampledImageArrayDynamicIndexing);
1566 } else if (isStorageImage(PointeeType)) {
1567 if (IsNonUniform)
1568 Handler.addRequirements(
1569 SPIRV::Capability::StorageImageArrayNonUniformIndexingEXT);
1570 else if (!FirstIndexIsConstant)
1571 Handler.addRequirements(
1572 SPIRV::Capability::StorageImageArrayDynamicIndexing);
1573 }
1574}
1575
1577 if (TypeInst->getOpcode() != SPIRV::OpTypeImage)
1578 return false;
1579 assert(TypeInst->getOperand(7).isImm() && "The image format must be an imm.");
1580 return TypeInst->getOperand(7).getImm() == 0;
1581}
1582
1585 const SPIRVSubtarget &ST) {
1586 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product))
1587 Reqs.addExtension(SPIRV::Extension::SPV_KHR_integer_dot_product);
1588 Reqs.addCapability(SPIRV::Capability::DotProduct);
1589
1590 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1591 assert(MI.getOperand(2).isReg() && "Unexpected operand in dot");
1592 SPIRVTypeInst TypeDef = getRegType(MI.getOperand(2).getReg(), *MI.getMF(),
1593 ST.getSPIRVGlobalRegistry());
1594 assert(TypeDef && "Unexpected type instruction for dot input");
1595 if (TypeDef->getOpcode() == SPIRV::OpTypeInt) {
1596 assert(TypeDef->getOperand(1).getImm() == 32);
1597 Reqs.addCapability(SPIRV::Capability::DotProductInput4x8BitPacked);
1598 } else if (isVectorType(TypeDef)) {
1599 SPIRVTypeInst ScalarTypeDef =
1600 MRI.getVRegDef(TypeDef->getOperand(1).getReg());
1601 assert(ScalarTypeDef->getOpcode() == SPIRV::OpTypeInt);
1602 if (ScalarTypeDef->getOperand(1).getImm() == 8) {
1603 assert(TypeDef->getOperand(2).getImm() == 4 &&
1604 "Dot operand of 8-bit integer type requires 4 components");
1605 Reqs.addCapability(SPIRV::Capability::DotProductInput4x8Bit);
1606 } else {
1607 Reqs.addCapability(SPIRV::Capability::DotProductInputAll);
1608 }
1609 }
1610}
1611
1614 const SPIRVSubtarget &ST) {
1615 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
1616 SPIRVTypeInst PtrType =
1617 GR->getSPIRVTypeForVReg(MI.getOperand(4).getReg(), MI.getMF());
1618 if (PtrType) {
1619 MachineOperand ASOp = PtrType->getOperand(1);
1620 if (ASOp.isImm()) {
1621 unsigned AddrSpace = ASOp.getImm();
1622 if (AddrSpace != SPIRV::StorageClass::UniformConstant) {
1623 if (!ST.canUseExtension(
1625 SPV_EXT_relaxed_printf_string_address_space)) {
1626 report_fatal_error("SPV_EXT_relaxed_printf_string_address_space is "
1627 "required because printf uses a format string not "
1628 "in constant address space.",
1629 false);
1630 }
1631 Reqs.addExtension(
1632 SPIRV::Extension::SPV_EXT_relaxed_printf_string_address_space);
1633 }
1634 }
1635 }
1636}
1637
1640 const SPIRVSubtarget &ST, unsigned OpIdx) {
1641 if (MI.getNumOperands() <= OpIdx)
1642 return;
1643 uint32_t Mask = MI.getOperand(OpIdx).getImm();
1644 for (uint32_t I = 0; I < 32; ++I)
1645 if (Mask & (1U << I))
1646 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ImageOperandOperand,
1647 1U << I, ST);
1648}
1649
1650static inline void maybeAddScatterGatherReq(const MachineInstr &MI,
1652 const SPIRVSubtarget &ST) {
1653 assert(MI.getOperand(1).isReg());
1654 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1655 SPIRVTypeInst ElemTypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
1656 if (ElemTypeDef->getOpcode() == SPIRV::OpTypePointer &&
1657 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
1658 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_masked_gather_scatter);
1659 Reqs.addCapability(SPIRV::Capability::MaskedGatherScatterINTEL);
1660 }
1661}
1662
1665 const SPIRVSubtarget &ST) {
1666 SPIRV::RequirementHandler &Reqs = MAI.Reqs;
1667 unsigned Op = MI.getOpcode();
1668 switch (Op) {
1669 case SPIRV::OpMemoryModel: {
1670 int64_t Addr = MI.getOperand(0).getImm();
1671 Reqs.getAndAddRequirements(SPIRV::OperandCategory::AddressingModelOperand,
1672 Addr, ST);
1673 int64_t Mem = MI.getOperand(1).getImm();
1674 Reqs.getAndAddRequirements(SPIRV::OperandCategory::MemoryModelOperand, Mem,
1675 ST);
1676 break;
1677 }
1678 case SPIRV::OpEntryPoint: {
1679 int64_t Exe = MI.getOperand(0).getImm();
1680 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ExecutionModelOperand,
1681 Exe, ST);
1682 break;
1683 }
1684 case SPIRV::OpExecutionMode:
1685 case SPIRV::OpExecutionModeId: {
1686 int64_t Exe = MI.getOperand(1).getImm();
1687 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ExecutionModeOperand,
1688 Exe, ST);
1689 break;
1690 }
1691 case SPIRV::OpTypeMatrix:
1692 Reqs.addCapability(SPIRV::Capability::Matrix);
1693 break;
1694 case SPIRV::OpTypeInt: {
1695 unsigned BitWidth = MI.getOperand(1).getImm();
1696 if (BitWidth == 64)
1697 Reqs.addCapability(SPIRV::Capability::Int64);
1698 else if (BitWidth == 16)
1699 Reqs.addCapability(SPIRV::Capability::Int16);
1700 else if (BitWidth == 8)
1701 Reqs.addCapability(SPIRV::Capability::Int8);
1702 else if (BitWidth == 4 &&
1703 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_int4)) {
1704 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_int4);
1705 Reqs.addCapability(SPIRV::Capability::Int4TypeINTEL);
1706 } else if (BitWidth != 32) {
1707 if (!ST.canUseExtension(
1708 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers))
1710 "OpTypeInt type with a width other than 8, 16, 32 or 64 bits "
1711 "requires the following SPIR-V extension: "
1712 "SPV_ALTERA_arbitrary_precision_integers");
1713 Reqs.addExtension(
1714 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers);
1715 Reqs.addCapability(SPIRV::Capability::ArbitraryPrecisionIntegersALTERA);
1716 }
1717 break;
1718 }
1719 case SPIRV::OpDot: {
1720 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1721 SPIRVTypeInst TypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
1722 if (isBFloat16Type(TypeDef))
1723 Reqs.addCapability(SPIRV::Capability::BFloat16DotProductKHR);
1724 break;
1725 }
1726 case SPIRV::OpTypeFloat: {
1727 unsigned BitWidth = MI.getOperand(1).getImm();
1728 if (BitWidth == 64)
1729 Reqs.addCapability(SPIRV::Capability::Float64);
1730 else if (BitWidth == 16) {
1731 if (isBFloat16Type(&MI)) {
1732 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_bfloat16))
1733 report_fatal_error("OpTypeFloat type with bfloat requires the "
1734 "following SPIR-V extension: SPV_KHR_bfloat16",
1735 false);
1736 Reqs.addExtension(SPIRV::Extension::SPV_KHR_bfloat16);
1737 Reqs.addCapability(SPIRV::Capability::BFloat16TypeKHR);
1738 } else {
1739 Reqs.addCapability(SPIRV::Capability::Float16);
1740 }
1741 }
1742 break;
1743 }
1744 case SPIRV::OpTypeVector: {
1745 unsigned NumComponents = MI.getOperand(2).getImm();
1746 if (NumComponents == 8 || NumComponents == 16)
1747 Reqs.addCapability(SPIRV::Capability::Vector16);
1748 else if (requiresLongVectorEXT(NumComponents))
1749 // Such widths are only expressible as OpTypeVectorIdEXT.
1751 "OpTypeVector with " + Twine(NumComponents) +
1752 " components requires the following SPIR-V extension: "
1753 "SPV_EXT_long_vector");
1754
1755 maybeAddScatterGatherReq(MI, Reqs, ST);
1756 break;
1757 }
1758 case SPIRV::OpTypeVectorIdEXT: {
1759 if (!ST.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector))
1760 reportFatalUsageError("OpTypeVectorIdEXT requires the following SPIR-V "
1761 "extension: SPV_EXT_long_vector extension");
1762 Reqs.addExtension(SPIRV::Extension::SPV_EXT_long_vector);
1763 Reqs.addCapability(SPIRV::Capability::LongVectorEXT);
1764 maybeAddScatterGatherReq(MI, Reqs, ST);
1765 break;
1766 }
1767 case SPIRV::OpTypePointer: {
1768 auto SC = MI.getOperand(1).getImm();
1769 Reqs.getAndAddRequirements(SPIRV::OperandCategory::StorageClassOperand, SC,
1770 ST);
1771 // If it's a type of pointer to float16 targeting OpenCL, add Float16Buffer
1772 // capability.
1773 if (ST.isShader())
1774 break;
1775 assert(MI.getOperand(2).isReg());
1776 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1777 SPIRVTypeInst TypeDef = MRI.getVRegDef(MI.getOperand(2).getReg());
1778 if ((TypeDef->getNumOperands() == 2) &&
1779 (TypeDef->getOpcode() == SPIRV::OpTypeFloat) &&
1780 (TypeDef->getOperand(1).getImm() == 16))
1781 Reqs.addCapability(SPIRV::Capability::Float16Buffer);
1782 break;
1783 }
1784 case SPIRV::OpExtInst: {
1785 if (MI.getOperand(2).getImm() ==
1786 static_cast<int64_t>(
1787 SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100)) {
1788 Reqs.addExtension(SPIRV::Extension::SPV_KHR_non_semantic_info);
1789 break;
1790 }
1791 if (MI.getOperand(3).getImm() ==
1792 static_cast<int64_t>(SPIRV::OpenCLExtInst::printf)) {
1793 addPrintfRequirements(MI, Reqs, ST);
1794 break;
1795 }
1796 if (MI.getOperand(2).getImm() ==
1797 static_cast<int64_t>(SPIRV::InstructionSet::OpenCL_std)) {
1798 const MachineFunction *MF = MI.getMF();
1799 const MachineRegisterInfo &MRI = MF->getRegInfo();
1800 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
1801
1802 auto IsBFloat16 = [&](SPIRVTypeInst TypeDef) {
1803 if (TypeDef && TypeDef->getOpcode() == SPIRV::OpTypeVector)
1804 TypeDef = MRI.getVRegDef(TypeDef->getOperand(1).getReg());
1805 return isBFloat16Type(TypeDef);
1806 };
1807
1808 // Result type is operand 1; arguments start at operand 4.
1809 bool UsesBFloat16 = IsBFloat16(MRI.getVRegDef(MI.getOperand(1).getReg()));
1810 for (unsigned I = 4, E = MI.getNumOperands(); I < E && !UsesBFloat16;
1811 ++I) {
1812 const MachineOperand &MO = MI.getOperand(I);
1813 if (MO.isReg())
1814 UsesBFloat16 = IsBFloat16(GR->getResultType(
1815 MO.getReg(), const_cast<MachineFunction *>(MF)));
1816 }
1817
1818 if (UsesBFloat16) {
1819 if (!ST.canUseExtension(
1820 SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic)) {
1822 MI, "OpenCL Extended instructions with bfloat16 require the "
1823 "following SPIR-V extension: SPV_INTEL_bfloat16_arithmetic");
1824 break;
1825 }
1826 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic);
1827 Reqs.addCapability(SPIRV::Capability::BFloat16ArithmeticINTEL);
1828 }
1829 }
1830 break;
1831 }
1832 case SPIRV::OpAliasDomainDeclINTEL:
1833 case SPIRV::OpAliasScopeDeclINTEL:
1834 case SPIRV::OpAliasScopeListDeclINTEL: {
1835 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing);
1836 Reqs.addCapability(SPIRV::Capability::MemoryAccessAliasingINTEL);
1837 break;
1838 }
1839 case SPIRV::OpBitReverse:
1840 case SPIRV::OpBitFieldInsert:
1841 case SPIRV::OpBitFieldSExtract:
1842 case SPIRV::OpBitFieldUExtract:
1843 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions)) {
1844 Reqs.addCapability(SPIRV::Capability::Shader);
1845 break;
1846 }
1847 Reqs.addExtension(SPIRV::Extension::SPV_KHR_bit_instructions);
1848 Reqs.addCapability(SPIRV::Capability::BitInstructions);
1849 break;
1850 case SPIRV::OpTypeRuntimeArray:
1851 Reqs.addCapability(SPIRV::Capability::Shader);
1852 break;
1853 case SPIRV::OpTypeOpaque:
1854 case SPIRV::OpTypeEvent:
1855 Reqs.addCapability(SPIRV::Capability::Kernel);
1856 break;
1857 case SPIRV::OpTypePipe:
1858 case SPIRV::OpTypeReserveId:
1859 Reqs.addCapability(SPIRV::Capability::Pipes);
1860 break;
1861 case SPIRV::OpTypePipeStorage:
1862 Reqs.addCapability(SPIRV::Capability::PipeStorage);
1863 break;
1864 case SPIRV::OpTypeDeviceEvent:
1865 case SPIRV::OpTypeQueue:
1866 case SPIRV::OpBuildNDRange:
1867 case SPIRV::OpEnqueueKernel:
1868 case SPIRV::OpGetKernelNDrangeSubGroupCount:
1869 case SPIRV::OpGetKernelNDrangeMaxSubGroupSize:
1870 case SPIRV::OpGetKernelWorkGroupSize:
1871 case SPIRV::OpGetKernelPreferredWorkGroupSizeMultiple:
1872 Reqs.addCapability(SPIRV::Capability::DeviceEnqueue);
1873 break;
1874 case SPIRV::OpDecorate:
1875 case SPIRV::OpDecorateId:
1876 case SPIRV::OpDecorateString:
1877 addOpDecorateReqs(MI, 1, Reqs, ST);
1878 break;
1879 case SPIRV::OpMemberDecorate:
1880 case SPIRV::OpMemberDecorateString:
1881 addOpDecorateReqs(MI, 2, Reqs, ST);
1882 break;
1883 case SPIRV::OpInBoundsPtrAccessChain:
1884 Reqs.addCapability(SPIRV::Capability::Addresses);
1885 break;
1886 case SPIRV::OpConstantSampler:
1887 Reqs.addCapability(SPIRV::Capability::LiteralSampler);
1888 break;
1889 case SPIRV::OpInBoundsAccessChain:
1890 case SPIRV::OpAccessChain:
1891 addOpAccessChainReqs(MI, Reqs, ST);
1892 break;
1893 case SPIRV::OpTypeImage:
1894 addOpTypeImageReqs(MI, Reqs, ST);
1895 break;
1896 case SPIRV::OpTypeSampler:
1897 if (!ST.isShader()) {
1898 Reqs.addCapability(SPIRV::Capability::ImageBasic);
1899 }
1900 break;
1901 case SPIRV::OpTypeForwardPointer:
1902 // TODO: check if it's OpenCL's kernel.
1903 Reqs.addCapability(SPIRV::Capability::Addresses);
1904 break;
1905 case SPIRV::OpAtomicFlagTestAndSet:
1906 case SPIRV::OpAtomicLoad:
1907 case SPIRV::OpAtomicStore:
1908 case SPIRV::OpAtomicExchange:
1909 case SPIRV::OpAtomicCompareExchange:
1910 case SPIRV::OpAtomicCompareExchangeWeak:
1911 case SPIRV::OpAtomicIIncrement:
1912 case SPIRV::OpAtomicIDecrement:
1913 case SPIRV::OpAtomicIAdd:
1914 case SPIRV::OpAtomicISub:
1915 case SPIRV::OpAtomicUMin:
1916 case SPIRV::OpAtomicUMax:
1917 case SPIRV::OpAtomicSMin:
1918 case SPIRV::OpAtomicSMax:
1919 case SPIRV::OpAtomicAnd:
1920 case SPIRV::OpAtomicOr:
1921 case SPIRV::OpAtomicXor: {
1922 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1923 SPIRVTypeInst TypeDef;
1924 if (Op == SPIRV::OpAtomicStore) {
1925 assert(MI.getOperand(3).isReg());
1926 TypeDef = getRegType(MI.getOperand(3).getReg(), *MI.getMF(),
1927 ST.getSPIRVGlobalRegistry());
1928 assert(TypeDef && "Unexpected type instruction for OpAtomicStore");
1929 } else {
1930 assert(MI.getOperand(1).isReg() && "Unexpected operand in atomic");
1931 TypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
1932 }
1933
1934 if (TypeDef->getOpcode() == SPIRV::OpTypeInt) {
1935 unsigned BitWidth = TypeDef->getOperand(1).getImm();
1936 if (BitWidth == 64)
1937 Reqs.addCapability(SPIRV::Capability::Int64Atomics);
1938 else if (BitWidth == 16) {
1939 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics))
1941 "16-bit integer atomic operations require the following SPIR-V "
1942 "extension: SPV_INTEL_16bit_atomics",
1943 false);
1944 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics);
1945 switch (Op) {
1946 case SPIRV::OpAtomicLoad:
1947 case SPIRV::OpAtomicStore:
1948 case SPIRV::OpAtomicExchange:
1949 case SPIRV::OpAtomicCompareExchange:
1950 case SPIRV::OpAtomicCompareExchangeWeak:
1951 Reqs.addCapability(
1952 SPIRV::Capability::AtomicInt16CompareExchangeINTEL);
1953 break;
1954 default:
1955 Reqs.addCapability(SPIRV::Capability::Int16AtomicsINTEL);
1956 break;
1957 }
1958 }
1959 } else if (isBFloat16Type(TypeDef)) {
1960 if (is_contained({SPIRV::OpAtomicLoad, SPIRV::OpAtomicStore,
1961 SPIRV::OpAtomicExchange},
1962 Op)) {
1963 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics))
1965 "The atomic bfloat16 instruction requires the following SPIR-V "
1966 "extension: SPV_INTEL_16bit_atomics",
1967 false);
1968 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics);
1969 Reqs.addCapability(SPIRV::Capability::AtomicBFloat16LoadStoreINTEL);
1970 }
1971 }
1972 break;
1973 }
1974 case SPIRV::OpGroupNonUniformIAdd:
1975 case SPIRV::OpGroupNonUniformFAdd:
1976 case SPIRV::OpGroupNonUniformIMul:
1977 case SPIRV::OpGroupNonUniformFMul:
1978 case SPIRV::OpGroupNonUniformSMin:
1979 case SPIRV::OpGroupNonUniformUMin:
1980 case SPIRV::OpGroupNonUniformFMin:
1981 case SPIRV::OpGroupNonUniformSMax:
1982 case SPIRV::OpGroupNonUniformUMax:
1983 case SPIRV::OpGroupNonUniformFMax:
1984 case SPIRV::OpGroupNonUniformBitwiseAnd:
1985 case SPIRV::OpGroupNonUniformBitwiseOr:
1986 case SPIRV::OpGroupNonUniformBitwiseXor:
1987 case SPIRV::OpGroupNonUniformLogicalAnd:
1988 case SPIRV::OpGroupNonUniformLogicalOr:
1989 case SPIRV::OpGroupNonUniformLogicalXor: {
1990 assert(MI.getOperand(3).isImm());
1991 int64_t GroupOp = MI.getOperand(3).getImm();
1992 switch (GroupOp) {
1993 case SPIRV::GroupOperation::Reduce:
1994 case SPIRV::GroupOperation::InclusiveScan:
1995 case SPIRV::GroupOperation::ExclusiveScan:
1996 Reqs.addCapability(SPIRV::Capability::GroupNonUniformArithmetic);
1997 break;
1998 case SPIRV::GroupOperation::ClusteredReduce:
1999 Reqs.addCapability(SPIRV::Capability::GroupNonUniformClustered);
2000 break;
2001 case SPIRV::GroupOperation::PartitionedReduceNV:
2002 case SPIRV::GroupOperation::PartitionedInclusiveScanNV:
2003 case SPIRV::GroupOperation::PartitionedExclusiveScanNV:
2004 if (ST.canUseExtension(
2005 SPIRV::Extension::SPV_EXT_shader_subgroup_partitioned))
2006 Reqs.addExtension(
2007 SPIRV::Extension::SPV_EXT_shader_subgroup_partitioned);
2008 else
2009 Reqs.addExtension(SPIRV::Extension::SPV_NV_shader_subgroup_partitioned);
2010 Reqs.addCapability(SPIRV::Capability::GroupNonUniformPartitionedNV);
2011 break;
2012 }
2013 break;
2014 }
2015 case SPIRV::OpGroupNonUniformQuadSwap:
2016 Reqs.addCapability(SPIRV::Capability::GroupNonUniformQuad);
2017 break;
2018 case SPIRV::OpImageQueryLod:
2019 Reqs.addCapability(SPIRV::Capability::ImageQuery);
2020 break;
2021 case SPIRV::OpImageQuerySize:
2022 case SPIRV::OpImageQuerySizeLod:
2023 case SPIRV::OpImageQueryLevels:
2024 case SPIRV::OpImageQuerySamples:
2025 if (ST.isShader())
2026 Reqs.addCapability(SPIRV::Capability::ImageQuery);
2027 break;
2028 case SPIRV::OpImageQueryFormat: {
2029 Register ResultReg = MI.getOperand(0).getReg();
2030 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
2031 static const unsigned CompareOps[] = {
2032 SPIRV::OpIEqual, SPIRV::OpINotEqual,
2033 SPIRV::OpUGreaterThan, SPIRV::OpUGreaterThanEqual,
2034 SPIRV::OpULessThan, SPIRV::OpULessThanEqual,
2035 SPIRV::OpSGreaterThan, SPIRV::OpSGreaterThanEqual,
2036 SPIRV::OpSLessThan, SPIRV::OpSLessThanEqual};
2037
2038 auto CheckAndAddExtension = [&](int64_t ImmVal) {
2039 if (ImmVal == 4323 || ImmVal == 4324) {
2040 if (ST.canUseExtension(SPIRV::Extension::SPV_EXT_image_raw10_raw12))
2041 Reqs.addExtension(SPIRV::Extension::SPV_EXT_image_raw10_raw12);
2042 else
2043 report_fatal_error("This requires the "
2044 "SPV_EXT_image_raw10_raw12 extension");
2045 }
2046 };
2047
2048 for (MachineInstr &UseInst : MRI.use_instructions(ResultReg)) {
2049 unsigned Opc = UseInst.getOpcode();
2050
2051 if (Opc == SPIRV::OpSwitch) {
2052 for (const MachineOperand &Op : UseInst.operands())
2053 if (Op.isImm())
2054 CheckAndAddExtension(Op.getImm());
2055 } else if (llvm::is_contained(CompareOps, Opc)) {
2056 for (unsigned i = 1; i < UseInst.getNumOperands(); ++i) {
2057 Register UseReg = UseInst.getOperand(i).getReg();
2058 MachineInstr *ConstInst = MRI.getVRegDef(UseReg);
2059 if (ConstInst && ConstInst->getOpcode() == SPIRV::OpConstantI) {
2060 int64_t ImmVal = ConstInst->getOperand(2).getImm();
2061 if (ImmVal)
2062 CheckAndAddExtension(ImmVal);
2063 }
2064 }
2065 }
2066 }
2067 break;
2068 }
2069
2070 case SPIRV::OpGroupNonUniformShuffle:
2071 case SPIRV::OpGroupNonUniformShuffleXor:
2072 Reqs.addCapability(SPIRV::Capability::GroupNonUniformShuffle);
2073 break;
2074 case SPIRV::OpGroupNonUniformShuffleUp:
2075 case SPIRV::OpGroupNonUniformShuffleDown:
2076 Reqs.addCapability(SPIRV::Capability::GroupNonUniformShuffleRelative);
2077 break;
2078 case SPIRV::OpGroupAll:
2079 case SPIRV::OpGroupAny:
2080 case SPIRV::OpGroupBroadcast:
2081 case SPIRV::OpGroupIAdd:
2082 case SPIRV::OpGroupFAdd:
2083 case SPIRV::OpGroupFMin:
2084 case SPIRV::OpGroupUMin:
2085 case SPIRV::OpGroupSMin:
2086 case SPIRV::OpGroupFMax:
2087 case SPIRV::OpGroupUMax:
2088 case SPIRV::OpGroupSMax:
2089 Reqs.addCapability(SPIRV::Capability::Groups);
2090 break;
2091 case SPIRV::OpGroupNonUniformElect:
2092 Reqs.addCapability(SPIRV::Capability::GroupNonUniform);
2093 break;
2094 case SPIRV::OpGroupNonUniformAll:
2095 case SPIRV::OpGroupNonUniformAny:
2096 case SPIRV::OpGroupNonUniformAllEqual:
2097 Reqs.addCapability(SPIRV::Capability::GroupNonUniformVote);
2098 break;
2099 case SPIRV::OpGroupNonUniformBroadcast:
2100 case SPIRV::OpGroupNonUniformBroadcastFirst:
2101 case SPIRV::OpGroupNonUniformBallot:
2102 case SPIRV::OpGroupNonUniformInverseBallot:
2103 case SPIRV::OpGroupNonUniformBallotBitExtract:
2104 case SPIRV::OpGroupNonUniformBallotBitCount:
2105 case SPIRV::OpGroupNonUniformBallotFindLSB:
2106 case SPIRV::OpGroupNonUniformBallotFindMSB:
2107 Reqs.addCapability(SPIRV::Capability::GroupNonUniformBallot);
2108 break;
2109 case SPIRV::OpSubgroupShuffleINTEL:
2110 case SPIRV::OpSubgroupShuffleDownINTEL:
2111 case SPIRV::OpSubgroupShuffleUpINTEL:
2112 case SPIRV::OpSubgroupShuffleXorINTEL:
2113 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
2114 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
2115 Reqs.addCapability(SPIRV::Capability::SubgroupShuffleINTEL);
2116 }
2117 break;
2118 case SPIRV::OpSubgroupBlockReadINTEL:
2119 case SPIRV::OpSubgroupBlockWriteINTEL:
2120 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
2121 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
2122 Reqs.addCapability(SPIRV::Capability::SubgroupBufferBlockIOINTEL);
2123 }
2124 break;
2125 case SPIRV::OpSubgroupImageBlockReadINTEL:
2126 case SPIRV::OpSubgroupImageBlockWriteINTEL:
2127 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
2128 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
2129 Reqs.addCapability(SPIRV::Capability::SubgroupImageBlockIOINTEL);
2130 }
2131 break;
2132 case SPIRV::OpSubgroupImageMediaBlockReadINTEL:
2133 case SPIRV::OpSubgroupImageMediaBlockWriteINTEL:
2134 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_media_block_io)) {
2135 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_media_block_io);
2136 Reqs.addCapability(SPIRV::Capability::SubgroupImageMediaBlockIOINTEL);
2137 }
2138 break;
2139 case SPIRV::OpAssumeTrueKHR:
2140 case SPIRV::OpExpectKHR:
2141 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) {
2142 Reqs.addExtension(SPIRV::Extension::SPV_KHR_expect_assume);
2143 Reqs.addCapability(SPIRV::Capability::ExpectAssumeKHR);
2144 }
2145 break;
2146 case SPIRV::OpFmaKHR:
2147 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_fma)) {
2148 Reqs.addExtension(SPIRV::Extension::SPV_KHR_fma);
2149 Reqs.addCapability(SPIRV::Capability::FmaKHR);
2150 }
2151 break;
2152 case SPIRV::OpPtrCastToCrossWorkgroupINTEL:
2153 case SPIRV::OpCrossWorkgroupCastToPtrINTEL:
2154 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes)) {
2155 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes);
2156 Reqs.addCapability(SPIRV::Capability::USMStorageClassesINTEL);
2157 }
2158 break;
2159 case SPIRV::OpConstantFunctionPointerINTEL:
2160 case SPIRV::OpFunctionPointerCallINTEL:
2161 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)) {
2162 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
2163 Reqs.addCapability(SPIRV::Capability::FunctionPointersINTEL);
2164 }
2165 break;
2166 case SPIRV::OpGroupNonUniformRotateKHR:
2167 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_subgroup_rotate))
2168 report_fatal_error("OpGroupNonUniformRotateKHR instruction requires the "
2169 "following SPIR-V extension: SPV_KHR_subgroup_rotate",
2170 false);
2171 Reqs.addExtension(SPIRV::Extension::SPV_KHR_subgroup_rotate);
2172 Reqs.addCapability(SPIRV::Capability::GroupNonUniformRotateKHR);
2173 Reqs.addCapability(SPIRV::Capability::GroupNonUniform);
2174 break;
2175 case SPIRV::OpFixedCosALTERA:
2176 case SPIRV::OpFixedSinALTERA:
2177 case SPIRV::OpFixedCosPiALTERA:
2178 case SPIRV::OpFixedSinPiALTERA:
2179 case SPIRV::OpFixedExpALTERA:
2180 case SPIRV::OpFixedLogALTERA:
2181 case SPIRV::OpFixedRecipALTERA:
2182 case SPIRV::OpFixedSqrtALTERA:
2183 case SPIRV::OpFixedSinCosALTERA:
2184 case SPIRV::OpFixedSinCosPiALTERA:
2185 case SPIRV::OpFixedRsqrtALTERA:
2186 if (!ST.canUseExtension(
2187 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_fixed_point))
2188 report_fatal_error("This instruction requires the "
2189 "following SPIR-V extension: "
2190 "SPV_ALTERA_arbitrary_precision_fixed_point",
2191 false);
2192 Reqs.addExtension(
2193 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_fixed_point);
2194 Reqs.addCapability(SPIRV::Capability::ArbitraryPrecisionFixedPointALTERA);
2195 break;
2196 case SPIRV::OpGroupIMulKHR:
2197 case SPIRV::OpGroupFMulKHR:
2198 case SPIRV::OpGroupBitwiseAndKHR:
2199 case SPIRV::OpGroupBitwiseOrKHR:
2200 case SPIRV::OpGroupBitwiseXorKHR:
2201 case SPIRV::OpGroupLogicalAndKHR:
2202 case SPIRV::OpGroupLogicalOrKHR:
2203 case SPIRV::OpGroupLogicalXorKHR:
2204 if (ST.canUseExtension(
2205 SPIRV::Extension::SPV_KHR_uniform_group_instructions)) {
2206 Reqs.addExtension(SPIRV::Extension::SPV_KHR_uniform_group_instructions);
2207 Reqs.addCapability(SPIRV::Capability::GroupUniformArithmeticKHR);
2208 }
2209 break;
2210 case SPIRV::OpReadClockKHR:
2211 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_shader_clock))
2212 report_fatal_error("OpReadClockKHR instruction requires the "
2213 "following SPIR-V extension: SPV_KHR_shader_clock",
2214 false);
2215 Reqs.addExtension(SPIRV::Extension::SPV_KHR_shader_clock);
2216 Reqs.addCapability(SPIRV::Capability::ShaderClockKHR);
2217 break;
2218 case SPIRV::OpAbortKHR:
2219 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort))
2220 report_fatal_error("OpAbortKHR instruction requires the "
2221 "following SPIR-V extension: SPV_KHR_abort",
2222 false);
2223 Reqs.addExtension(SPIRV::Extension::SPV_KHR_abort);
2224 Reqs.addCapability(SPIRV::Capability::AbortKHR);
2225 break;
2226 case SPIRV::OpPoisonKHR:
2227 case SPIRV::OpFreezeKHR:
2228 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_poison_freeze))
2229 report_fatal_error("OpPoisonKHR/OpFreezeKHR instruction requires the "
2230 "following SPIR-V extension: SPV_KHR_poison_freeze",
2231 false);
2232 Reqs.addExtension(SPIRV::Extension::SPV_KHR_poison_freeze);
2233 Reqs.addCapability(SPIRV::Capability::PoisonFreezeKHR);
2234 break;
2235 case SPIRV::OpAtomicFAddEXT:
2236 case SPIRV::OpAtomicFMinEXT:
2237 case SPIRV::OpAtomicFMaxEXT:
2238 AddAtomicFloatRequirements(MI, Reqs, ST);
2239 break;
2240 case SPIRV::OpConvertBF16ToFINTEL:
2241 case SPIRV::OpConvertFToBF16INTEL:
2242 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bfloat16_conversion)) {
2243 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_conversion);
2244 Reqs.addCapability(SPIRV::Capability::BFloat16ConversionINTEL);
2245 }
2246 break;
2247 case SPIRV::OpRoundFToTF32INTEL:
2248 if (ST.canUseExtension(
2249 SPIRV::Extension::SPV_INTEL_tensor_float32_conversion)) {
2250 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_tensor_float32_conversion);
2251 Reqs.addCapability(SPIRV::Capability::TensorFloat32RoundingINTEL);
2252 }
2253 break;
2254 case SPIRV::OpVariableLengthArrayINTEL:
2255 case SPIRV::OpSaveMemoryINTEL:
2256 case SPIRV::OpRestoreMemoryINTEL:
2257 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array)) {
2258 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_variable_length_array);
2259 Reqs.addCapability(SPIRV::Capability::VariableLengthArrayINTEL);
2260 }
2261 break;
2262 case SPIRV::OpUntypedVariableLengthArrayINTEL:
2263 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array)) {
2264 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_variable_length_array);
2265 Reqs.addCapability(SPIRV::Capability::UntypedVariableLengthArrayINTEL);
2266 }
2267 break;
2268 case SPIRV::OpAsmTargetINTEL:
2269 case SPIRV::OpAsmINTEL:
2270 case SPIRV::OpAsmCallINTEL:
2271 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_inline_assembly)) {
2272 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_inline_assembly);
2273 Reqs.addCapability(SPIRV::Capability::AsmINTEL);
2274 }
2275 break;
2276 case SPIRV::OpTypeCooperativeMatrixKHR: {
2277 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix))
2279 "OpTypeCooperativeMatrixKHR type requires the "
2280 "following SPIR-V extension: SPV_KHR_cooperative_matrix",
2281 false);
2282 Reqs.addExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix);
2283 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixKHR);
2284 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
2285 SPIRVTypeInst TypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
2286 if (isBFloat16Type(TypeDef))
2287 Reqs.addCapability(SPIRV::Capability::BFloat16CooperativeMatrixKHR);
2288 break;
2289 }
2290 case SPIRV::OpArithmeticFenceEXT:
2291 if (!ST.canUseExtension(SPIRV::Extension::SPV_EXT_arithmetic_fence))
2292 report_fatal_error("OpArithmeticFenceEXT requires the "
2293 "following SPIR-V extension: SPV_EXT_arithmetic_fence",
2294 false);
2295 Reqs.addExtension(SPIRV::Extension::SPV_EXT_arithmetic_fence);
2296 Reqs.addCapability(SPIRV::Capability::ArithmeticFenceEXT);
2297 break;
2298 case SPIRV::OpControlBarrierArriveINTEL:
2299 case SPIRV::OpControlBarrierWaitINTEL:
2300 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_split_barrier)) {
2301 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_split_barrier);
2302 Reqs.addCapability(SPIRV::Capability::SplitBarrierINTEL);
2303 }
2304 break;
2305 case SPIRV::OpCooperativeMatrixMulAddKHR: {
2306 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix))
2307 report_fatal_error("Cooperative matrix instructions require the "
2308 "following SPIR-V extension: "
2309 "SPV_KHR_cooperative_matrix",
2310 false);
2311 Reqs.addExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix);
2312 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixKHR);
2313 constexpr unsigned MulAddMaxSize = 6;
2314 if (MI.getNumOperands() != MulAddMaxSize)
2315 break;
2316 const int64_t CoopOperands = MI.getOperand(MulAddMaxSize - 1).getImm();
2317 if (CoopOperands &
2318 SPIRV::CooperativeMatrixOperands::MatrixAAndBTF32ComponentsINTEL) {
2319 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2320 report_fatal_error("MatrixAAndBTF32ComponentsINTEL type interpretation "
2321 "require the following SPIR-V extension: "
2322 "SPV_INTEL_joint_matrix",
2323 false);
2324 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2325 Reqs.addCapability(
2326 SPIRV::Capability::CooperativeMatrixTF32ComponentTypeINTEL);
2327 }
2328 if (CoopOperands & SPIRV::CooperativeMatrixOperands::
2329 MatrixAAndBBFloat16ComponentsINTEL ||
2330 CoopOperands &
2331 SPIRV::CooperativeMatrixOperands::MatrixCBFloat16ComponentsINTEL ||
2332 CoopOperands & SPIRV::CooperativeMatrixOperands::
2333 MatrixResultBFloat16ComponentsINTEL) {
2334 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2335 report_fatal_error("***BF16ComponentsINTEL type interpretations "
2336 "require the following SPIR-V extension: "
2337 "SPV_INTEL_joint_matrix",
2338 false);
2339 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2340 Reqs.addCapability(
2341 SPIRV::Capability::CooperativeMatrixBFloat16ComponentTypeINTEL);
2342 }
2343 break;
2344 }
2345 case SPIRV::OpCooperativeMatrixLoadKHR:
2346 case SPIRV::OpCooperativeMatrixStoreKHR:
2347 case SPIRV::OpCooperativeMatrixLoadCheckedINTEL:
2348 case SPIRV::OpCooperativeMatrixStoreCheckedINTEL:
2349 case SPIRV::OpCooperativeMatrixPrefetchINTEL: {
2350 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix))
2351 report_fatal_error("Cooperative matrix instructions require the "
2352 "following SPIR-V extension: "
2353 "SPV_KHR_cooperative_matrix",
2354 false);
2355 Reqs.addExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix);
2356 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixKHR);
2357
2358 // Check Layout operand in case if it's not a standard one and add the
2359 // appropriate capability.
2360 unsigned LayoutNum;
2361 switch (Op) {
2362 case SPIRV::OpCooperativeMatrixLoadKHR:
2363 LayoutNum = 3;
2364 break;
2365 case SPIRV::OpCooperativeMatrixStoreKHR:
2366 LayoutNum = 2;
2367 break;
2368 case SPIRV::OpCooperativeMatrixLoadCheckedINTEL:
2369 LayoutNum = 5;
2370 break;
2371 case SPIRV::OpCooperativeMatrixStoreCheckedINTEL:
2372 case SPIRV::OpCooperativeMatrixPrefetchINTEL:
2373 LayoutNum = 4;
2374 break;
2375 default:
2376 llvm_unreachable("unexpected cooperative matrix opcode");
2377 }
2378 Register RegLayout = MI.getOperand(LayoutNum).getReg();
2379 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
2380 MachineInstr *MILayout = MRI.getUniqueVRegDef(RegLayout);
2381 if (MILayout->getOpcode() == SPIRV::OpConstantI) {
2382 const unsigned LayoutVal = MILayout->getOperand(2).getImm();
2383 if (LayoutVal ==
2384 static_cast<unsigned>(SPIRV::CooperativeMatrixLayout::PackedINTEL)) {
2385 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2386 report_fatal_error("PackedINTEL layout require the following SPIR-V "
2387 "extension: SPV_INTEL_joint_matrix",
2388 false);
2389 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2390 Reqs.addCapability(SPIRV::Capability::PackedCooperativeMatrixINTEL);
2391 }
2392 }
2393
2394 // Nothing to do.
2395 if (Op == SPIRV::OpCooperativeMatrixLoadKHR ||
2396 Op == SPIRV::OpCooperativeMatrixStoreKHR)
2397 break;
2398
2399 std::string InstName;
2400 switch (Op) {
2401 case SPIRV::OpCooperativeMatrixPrefetchINTEL:
2402 InstName = "OpCooperativeMatrixPrefetchINTEL";
2403 break;
2404 case SPIRV::OpCooperativeMatrixLoadCheckedINTEL:
2405 InstName = "OpCooperativeMatrixLoadCheckedINTEL";
2406 break;
2407 case SPIRV::OpCooperativeMatrixStoreCheckedINTEL:
2408 InstName = "OpCooperativeMatrixStoreCheckedINTEL";
2409 break;
2410 }
2411
2412 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix)) {
2413 const std::string ErrorMsg =
2414 InstName + " instruction requires the "
2415 "following SPIR-V extension: SPV_INTEL_joint_matrix";
2416 report_fatal_error(ErrorMsg.c_str(), false);
2417 }
2418 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2419 if (Op == SPIRV::OpCooperativeMatrixPrefetchINTEL) {
2420 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixPrefetchINTEL);
2421 break;
2422 }
2423 Reqs.addCapability(
2424 SPIRV::Capability::CooperativeMatrixCheckedInstructionsINTEL);
2425 break;
2426 }
2427 case SPIRV::OpCooperativeMatrixConstructCheckedINTEL:
2428 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2429 report_fatal_error("OpCooperativeMatrixConstructCheckedINTEL "
2430 "instructions require the following SPIR-V extension: "
2431 "SPV_INTEL_joint_matrix",
2432 false);
2433 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2434 Reqs.addCapability(
2435 SPIRV::Capability::CooperativeMatrixCheckedInstructionsINTEL);
2436 break;
2437 case SPIRV::OpReadPipeBlockingALTERA:
2438 case SPIRV::OpWritePipeBlockingALTERA:
2439 if (ST.canUseExtension(SPIRV::Extension::SPV_ALTERA_blocking_pipes)) {
2440 Reqs.addExtension(SPIRV::Extension::SPV_ALTERA_blocking_pipes);
2441 Reqs.addCapability(SPIRV::Capability::BlockingPipesALTERA);
2442 }
2443 break;
2444 case SPIRV::OpCooperativeMatrixGetElementCoordINTEL:
2445 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2446 report_fatal_error("OpCooperativeMatrixGetElementCoordINTEL requires the "
2447 "following SPIR-V extension: SPV_INTEL_joint_matrix",
2448 false);
2449 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2450 Reqs.addCapability(
2451 SPIRV::Capability::CooperativeMatrixInvocationInstructionsINTEL);
2452 break;
2453 case SPIRV::OpConvertHandleToImageINTEL:
2454 case SPIRV::OpConvertHandleToSamplerINTEL:
2455 case SPIRV::OpConvertHandleToSampledImageINTEL: {
2456 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bindless_images))
2457 report_fatal_error("OpConvertHandleTo[Image/Sampler/SampledImage]INTEL "
2458 "instructions require the following SPIR-V extension: "
2459 "SPV_INTEL_bindless_images",
2460 false);
2461 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
2462 SPIRV::AddressingModel::AddressingModel AddrModel = MAI.Addr;
2463 SPIRVTypeInst TyDef = GR->getSPIRVTypeForVReg(MI.getOperand(1).getReg());
2464 if (Op == SPIRV::OpConvertHandleToImageINTEL &&
2465 TyDef->getOpcode() != SPIRV::OpTypeImage) {
2466 report_fatal_error("Incorrect return type for the instruction "
2467 "OpConvertHandleToImageINTEL",
2468 false);
2469 } else if (Op == SPIRV::OpConvertHandleToSamplerINTEL &&
2470 TyDef->getOpcode() != SPIRV::OpTypeSampler) {
2471 report_fatal_error("Incorrect return type for the instruction "
2472 "OpConvertHandleToSamplerINTEL",
2473 false);
2474 } else if (Op == SPIRV::OpConvertHandleToSampledImageINTEL &&
2475 TyDef->getOpcode() != SPIRV::OpTypeSampledImage) {
2476 report_fatal_error("Incorrect return type for the instruction "
2477 "OpConvertHandleToSampledImageINTEL",
2478 false);
2479 }
2480 SPIRVTypeInst SpvTy =
2481 getRegType(MI.getOperand(2).getReg(), *MI.getMF(), GR);
2482 unsigned Bitwidth = GR->getScalarOrVectorBitWidth(SpvTy);
2483 if (!(Bitwidth == 32 && AddrModel == SPIRV::AddressingModel::Physical32) &&
2484 !(Bitwidth == 64 && AddrModel == SPIRV::AddressingModel::Physical64)) {
2486 "Parameter value must be a 32-bit scalar in case of "
2487 "Physical32 addressing model or a 64-bit scalar in case of "
2488 "Physical64 addressing model",
2489 false);
2490 }
2491 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bindless_images);
2492 Reqs.addCapability(SPIRV::Capability::BindlessImagesINTEL);
2493 break;
2494 }
2495 case SPIRV::OpSubgroup2DBlockLoadINTEL:
2496 case SPIRV::OpSubgroup2DBlockLoadTransposeINTEL:
2497 case SPIRV::OpSubgroup2DBlockLoadTransformINTEL:
2498 case SPIRV::OpSubgroup2DBlockPrefetchINTEL:
2499 case SPIRV::OpSubgroup2DBlockStoreINTEL: {
2500 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_2d_block_io))
2501 report_fatal_error("OpSubgroup2DBlock[Load/LoadTranspose/LoadTransform/"
2502 "Prefetch/Store]INTEL instructions require the "
2503 "following SPIR-V extension: SPV_INTEL_2d_block_io",
2504 false);
2505 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_2d_block_io);
2506 Reqs.addCapability(SPIRV::Capability::Subgroup2DBlockIOINTEL);
2507
2508 if (Op == SPIRV::OpSubgroup2DBlockLoadTransposeINTEL) {
2509 Reqs.addCapability(SPIRV::Capability::Subgroup2DBlockTransposeINTEL);
2510 break;
2511 }
2512 if (Op == SPIRV::OpSubgroup2DBlockLoadTransformINTEL) {
2513 Reqs.addCapability(SPIRV::Capability::Subgroup2DBlockTransformINTEL);
2514 break;
2515 }
2516 break;
2517 }
2518 case SPIRV::OpKill: {
2519 Reqs.addCapability(SPIRV::Capability::Shader);
2520 } break;
2521 case SPIRV::OpDemoteToHelperInvocation:
2522 Reqs.addCapability(SPIRV::Capability::DemoteToHelperInvocation);
2523
2524 if (ST.canUseExtension(
2525 SPIRV::Extension::SPV_EXT_demote_to_helper_invocation)) {
2526 if (!ST.isAtLeastSPIRVVer(llvm::VersionTuple(1, 6)))
2527 Reqs.addExtension(
2528 SPIRV::Extension::SPV_EXT_demote_to_helper_invocation);
2529 }
2530 break;
2531 case SPIRV::OpSDot:
2532 case SPIRV::OpUDot:
2533 case SPIRV::OpSUDot:
2534 case SPIRV::OpSDotAccSat:
2535 case SPIRV::OpUDotAccSat:
2536 case SPIRV::OpSUDotAccSat:
2537 AddDotProductRequirements(MI, Reqs, ST);
2538 break;
2539 case SPIRV::OpImageSampleImplicitLod:
2540 case SPIRV::OpImageFetch:
2541 Reqs.addCapability(SPIRV::Capability::Shader);
2542 addImageOperandReqs(MI, Reqs, ST, 4);
2543 break;
2544 case SPIRV::OpImageSampleExplicitLod:
2545 addImageOperandReqs(MI, Reqs, ST, 4);
2546 break;
2547 case SPIRV::OpImageSampleDrefImplicitLod:
2548 case SPIRV::OpImageSampleDrefExplicitLod:
2549 case SPIRV::OpImageDrefGather:
2550 case SPIRV::OpImageGather:
2551 Reqs.addCapability(SPIRV::Capability::Shader);
2552 addImageOperandReqs(MI, Reqs, ST, 5);
2553 break;
2554 case SPIRV::OpImageRead: {
2555 Register ImageReg = MI.getOperand(2).getReg();
2556 SPIRVTypeInst TypeDef = ST.getSPIRVGlobalRegistry()->getResultType(
2557 ImageReg, const_cast<MachineFunction *>(MI.getMF()));
2558 // OpImageRead and OpImageWrite can use Unknown Image Formats
2559 // when the Kernel capability is declared. In the OpenCL environment we are
2560 // not allowed to produce
2561 // StorageImageReadWithoutFormat/StorageImageWriteWithoutFormat, see
2562 // https://github.com/KhronosGroup/SPIRV-Headers/issues/487
2563
2564 if (isImageTypeWithUnknownFormat(TypeDef) && ST.isShader())
2565 Reqs.addCapability(SPIRV::Capability::StorageImageReadWithoutFormat);
2566 break;
2567 }
2568 case SPIRV::OpImageWrite: {
2569 Register ImageReg = MI.getOperand(0).getReg();
2570 SPIRVTypeInst TypeDef = ST.getSPIRVGlobalRegistry()->getResultType(
2571 ImageReg, const_cast<MachineFunction *>(MI.getMF()));
2572 // OpImageRead and OpImageWrite can use Unknown Image Formats
2573 // when the Kernel capability is declared. In the OpenCL environment we are
2574 // not allowed to produce
2575 // StorageImageReadWithoutFormat/StorageImageWriteWithoutFormat, see
2576 // https://github.com/KhronosGroup/SPIRV-Headers/issues/487
2577
2578 if (isImageTypeWithUnknownFormat(TypeDef) && ST.isShader())
2579 Reqs.addCapability(SPIRV::Capability::StorageImageWriteWithoutFormat);
2580 break;
2581 }
2582 case SPIRV::OpTypeStructContinuedINTEL:
2583 case SPIRV::OpConstantCompositeContinuedINTEL:
2584 case SPIRV::OpSpecConstantCompositeContinuedINTEL:
2585 case SPIRV::OpCompositeConstructContinuedINTEL: {
2586 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_long_composites))
2588 "Continued instructions require the "
2589 "following SPIR-V extension: SPV_INTEL_long_composites",
2590 false);
2591 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_long_composites);
2592 Reqs.addCapability(SPIRV::Capability::LongCompositesINTEL);
2593 break;
2594 }
2595 case SPIRV::OpArbitraryFloatEQALTERA:
2596 case SPIRV::OpArbitraryFloatGEALTERA:
2597 case SPIRV::OpArbitraryFloatGTALTERA:
2598 case SPIRV::OpArbitraryFloatLEALTERA:
2599 case SPIRV::OpArbitraryFloatLTALTERA:
2600 case SPIRV::OpArbitraryFloatCbrtALTERA:
2601 case SPIRV::OpArbitraryFloatCosALTERA:
2602 case SPIRV::OpArbitraryFloatCosPiALTERA:
2603 case SPIRV::OpArbitraryFloatExp10ALTERA:
2604 case SPIRV::OpArbitraryFloatExp2ALTERA:
2605 case SPIRV::OpArbitraryFloatExpALTERA:
2606 case SPIRV::OpArbitraryFloatExpm1ALTERA:
2607 case SPIRV::OpArbitraryFloatHypotALTERA:
2608 case SPIRV::OpArbitraryFloatLog10ALTERA:
2609 case SPIRV::OpArbitraryFloatLog1pALTERA:
2610 case SPIRV::OpArbitraryFloatLog2ALTERA:
2611 case SPIRV::OpArbitraryFloatLogALTERA:
2612 case SPIRV::OpArbitraryFloatRecipALTERA:
2613 case SPIRV::OpArbitraryFloatSinCosALTERA:
2614 case SPIRV::OpArbitraryFloatSinCosPiALTERA:
2615 case SPIRV::OpArbitraryFloatSinALTERA:
2616 case SPIRV::OpArbitraryFloatSinPiALTERA:
2617 case SPIRV::OpArbitraryFloatSqrtALTERA:
2618 case SPIRV::OpArbitraryFloatACosALTERA:
2619 case SPIRV::OpArbitraryFloatACosPiALTERA:
2620 case SPIRV::OpArbitraryFloatAddALTERA:
2621 case SPIRV::OpArbitraryFloatASinALTERA:
2622 case SPIRV::OpArbitraryFloatASinPiALTERA:
2623 case SPIRV::OpArbitraryFloatATan2ALTERA:
2624 case SPIRV::OpArbitraryFloatATanALTERA:
2625 case SPIRV::OpArbitraryFloatATanPiALTERA:
2626 case SPIRV::OpArbitraryFloatCastFromIntALTERA:
2627 case SPIRV::OpArbitraryFloatCastALTERA:
2628 case SPIRV::OpArbitraryFloatCastToIntALTERA:
2629 case SPIRV::OpArbitraryFloatDivALTERA:
2630 case SPIRV::OpArbitraryFloatMulALTERA:
2631 case SPIRV::OpArbitraryFloatPowALTERA:
2632 case SPIRV::OpArbitraryFloatPowNALTERA:
2633 case SPIRV::OpArbitraryFloatPowRALTERA:
2634 case SPIRV::OpArbitraryFloatRSqrtALTERA:
2635 case SPIRV::OpArbitraryFloatSubALTERA: {
2636 if (!ST.canUseExtension(
2637 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_floating_point))
2639 "Floating point instructions can't be translated correctly without "
2640 "enabled SPV_ALTERA_arbitrary_precision_floating_point extension!",
2641 false);
2642 Reqs.addExtension(
2643 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_floating_point);
2644 Reqs.addCapability(
2645 SPIRV::Capability::ArbitraryPrecisionFloatingPointALTERA);
2646 break;
2647 }
2648 case SPIRV::OpSubgroupMatrixMultiplyAccumulateINTEL: {
2649 if (!ST.canUseExtension(
2650 SPIRV::Extension::SPV_INTEL_subgroup_matrix_multiply_accumulate))
2652 "OpSubgroupMatrixMultiplyAccumulateINTEL instruction requires the "
2653 "following SPIR-V "
2654 "extension: SPV_INTEL_subgroup_matrix_multiply_accumulate",
2655 false);
2656 Reqs.addExtension(
2657 SPIRV::Extension::SPV_INTEL_subgroup_matrix_multiply_accumulate);
2658 Reqs.addCapability(
2659 SPIRV::Capability::SubgroupMatrixMultiplyAccumulateINTEL);
2660 break;
2661 }
2662 case SPIRV::OpBitwiseFunctionINTEL: {
2663 if (!ST.canUseExtension(
2664 SPIRV::Extension::SPV_INTEL_ternary_bitwise_function))
2666 "OpBitwiseFunctionINTEL instruction requires the following SPIR-V "
2667 "extension: SPV_INTEL_ternary_bitwise_function",
2668 false);
2669 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_ternary_bitwise_function);
2670 Reqs.addCapability(SPIRV::Capability::TernaryBitwiseFunctionINTEL);
2671 break;
2672 }
2673 case SPIRV::OpCopyMemorySized: {
2674 Reqs.addCapability(SPIRV::Capability::Addresses);
2675 // TODO: Add UntypedPointersKHR when implemented.
2676 break;
2677 }
2678 case SPIRV::OpTypeUntypedPointerKHR:
2679 Reqs.getAndAddRequirements(SPIRV::OperandCategory::StorageClassOperand,
2680 MI.getOperand(1).getImm(), ST);
2681 [[fallthrough]];
2682 case SPIRV::OpUntypedVariableKHR:
2683 case SPIRV::OpUntypedAccessChainKHR:
2684 case SPIRV::OpUntypedInBoundsAccessChainKHR:
2685 case SPIRV::OpUntypedPtrAccessChainKHR:
2686 case SPIRV::OpUntypedInBoundsPtrAccessChainKHR:
2687 case SPIRV::OpUntypedPrefetchKHR:
2688 case SPIRV::OpUntypedGroupAsyncCopyKHR: {
2689 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_untyped_pointers))
2690 report_fatal_error("Untyped pointer instructions require the following "
2691 "SPIR-V extension: SPV_KHR_untyped_pointers",
2692 false);
2693 Reqs.addExtension(SPIRV::Extension::SPV_KHR_untyped_pointers);
2694 Reqs.addCapability(SPIRV::Capability::UntypedPointersKHR);
2695 break;
2696 }
2697 case SPIRV::OpPredicatedLoadINTEL:
2698 case SPIRV::OpPredicatedStoreINTEL: {
2699 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_predicated_io))
2701 "OpPredicated[Load/Store]INTEL instructions require "
2702 "the following SPIR-V extension: SPV_INTEL_predicated_io",
2703 false);
2704 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_predicated_io);
2705 Reqs.addCapability(SPIRV::Capability::PredicatedIOINTEL);
2706 break;
2707 }
2708 case SPIRV::OpFAddS:
2709 case SPIRV::OpFSubS:
2710 case SPIRV::OpFMulS:
2711 case SPIRV::OpFDivS:
2712 case SPIRV::OpFRemS:
2713 case SPIRV::OpFMod:
2714 case SPIRV::OpFNegate:
2715 case SPIRV::OpFAddV:
2716 case SPIRV::OpFSubV:
2717 case SPIRV::OpFMulV:
2718 case SPIRV::OpFDivV:
2719 case SPIRV::OpFRemV:
2720 case SPIRV::OpFNegateV: {
2721 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
2722 SPIRVTypeInst TypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
2723 if (isVectorType(TypeDef))
2724 TypeDef = MRI.getVRegDef(TypeDef->getOperand(1).getReg());
2725 if (isBFloat16Type(TypeDef)) {
2726 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic))
2728 "Arithmetic instructions with bfloat16 arguments require the "
2729 "following SPIR-V extension: SPV_INTEL_bfloat16_arithmetic",
2730 false);
2731 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic);
2732 Reqs.addCapability(SPIRV::Capability::BFloat16ArithmeticINTEL);
2733 }
2734 break;
2735 }
2736 case SPIRV::OpOrdered:
2737 case SPIRV::OpUnordered:
2738 case SPIRV::OpFOrdEqual:
2739 case SPIRV::OpFOrdNotEqual:
2740 case SPIRV::OpFOrdLessThan:
2741 case SPIRV::OpFOrdLessThanEqual:
2742 case SPIRV::OpFOrdGreaterThan:
2743 case SPIRV::OpFOrdGreaterThanEqual:
2744 case SPIRV::OpFUnordEqual:
2745 case SPIRV::OpFUnordNotEqual:
2746 case SPIRV::OpFUnordLessThan:
2747 case SPIRV::OpFUnordLessThanEqual:
2748 case SPIRV::OpFUnordGreaterThan:
2749 case SPIRV::OpFUnordGreaterThanEqual: {
2750 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
2751 SPIRVTypeInst TypeDef = getRegType(MI.getOperand(2).getReg(), *MI.getMF(),
2752 ST.getSPIRVGlobalRegistry());
2753 assert(TypeDef && "Unexpected type instruction for comparison operand");
2754 if (isVectorType(TypeDef))
2755 TypeDef = MRI.getVRegDef(TypeDef->getOperand(1).getReg());
2756 if (isBFloat16Type(TypeDef)) {
2757 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic))
2759 "Relational instructions with bfloat16 arguments require the "
2760 "following SPIR-V extension: SPV_INTEL_bfloat16_arithmetic",
2761 false);
2762 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic);
2763 Reqs.addCapability(SPIRV::Capability::BFloat16ArithmeticINTEL);
2764 }
2765 break;
2766 }
2767 case SPIRV::OpDPdxCoarse:
2768 case SPIRV::OpDPdyCoarse:
2769 case SPIRV::OpDPdxFine:
2770 case SPIRV::OpDPdyFine: {
2771 Reqs.addCapability(SPIRV::Capability::DerivativeControl);
2772 break;
2773 }
2774 case SPIRV::OpLoopControlINTEL: {
2775 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_unstructured_loop_controls);
2776 Reqs.addCapability(SPIRV::Capability::UnstructuredLoopControlsINTEL);
2777 break;
2778 }
2779
2780 default:
2781 break;
2782 }
2783
2784 // If we require capability Shader, then we can remove the requirement for
2785 // the BitInstructions capability, since Shader is a superset capability
2786 // of BitInstructions.
2787 Reqs.removeCapabilityIf(SPIRV::Capability::BitInstructions,
2788 SPIRV::Capability::Shader);
2789}
2790
2792 MachineFunctionGetter GetMF, const SPIRVSubtarget &ST) {
2793 // Collect requirements for existing instructions.
2794 for (const Function &F : M) {
2795 MachineFunction *MF = GetMF(F);
2796 if (!MF)
2797 continue;
2798 for (const MachineBasicBlock &MBB : *MF)
2799 for (const MachineInstr &MI : MBB)
2800 addInstrRequirements(MI, MAI, ST);
2801 }
2802 // Collect requirements for OpExecutionMode instructions.
2803 auto Node = M.getNamedMetadata("spirv.ExecutionMode");
2804 if (Node) {
2805 bool RequireFloatControls = false, RequireIntelFloatControls2 = false,
2806 RequireKHRFloatControls2 = false,
2807 VerLower14 = !ST.isAtLeastSPIRVVer(VersionTuple(1, 4));
2808 bool HasIntelFloatControls2 =
2809 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_float_controls2);
2810 bool HasKHRFloatControls2 =
2811 ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2);
2812 for (unsigned i = 0; i < Node->getNumOperands(); i++) {
2813 MDNode *MDN = cast<MDNode>(Node->getOperand(i));
2814 const MDOperand &MDOp = MDN->getOperand(1);
2815 if (auto *CMeta = dyn_cast<ConstantAsMetadata>(MDOp)) {
2816 Constant *C = CMeta->getValue();
2817 if (ConstantInt *Const = dyn_cast<ConstantInt>(C)) {
2818 auto EM = Const->getZExtValue();
2819 // SPV_KHR_float_controls is not available until v1.4:
2820 // add SPV_KHR_float_controls if the version is too low
2821 switch (EM) {
2822 case SPIRV::ExecutionMode::DenormPreserve:
2823 case SPIRV::ExecutionMode::DenormFlushToZero:
2824 case SPIRV::ExecutionMode::RoundingModeRTE:
2825 case SPIRV::ExecutionMode::RoundingModeRTZ:
2826 RequireFloatControls = VerLower14;
2828 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2829 break;
2830 case SPIRV::ExecutionMode::RoundingModeRTPINTEL:
2831 case SPIRV::ExecutionMode::RoundingModeRTNINTEL:
2832 case SPIRV::ExecutionMode::FloatingPointModeALTINTEL:
2833 case SPIRV::ExecutionMode::FloatingPointModeIEEEINTEL:
2834 if (HasIntelFloatControls2) {
2835 RequireIntelFloatControls2 = true;
2837 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2838 }
2839 break;
2840 case SPIRV::ExecutionMode::FPFastMathDefault: {
2841 if (HasKHRFloatControls2) {
2842 RequireKHRFloatControls2 = true;
2844 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2845 }
2846 break;
2847 }
2848 case SPIRV::ExecutionMode::ContractionOff:
2849 case SPIRV::ExecutionMode::SignedZeroInfNanPreserve:
2850 if (HasKHRFloatControls2) {
2851 RequireKHRFloatControls2 = true;
2853 SPIRV::OperandCategory::ExecutionModeOperand,
2854 SPIRV::ExecutionMode::FPFastMathDefault, ST);
2855 } else {
2857 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2858 }
2859 break;
2860 default:
2862 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2863 }
2864 }
2865 }
2866 }
2867 if (RequireFloatControls &&
2868 ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls))
2869 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls);
2870 if (RequireIntelFloatControls2)
2871 MAI.Reqs.addExtension(SPIRV::Extension::SPV_INTEL_float_controls2);
2872 if (RequireKHRFloatControls2)
2873 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls2);
2874 }
2875 for (const Function &F : M) {
2876 if (F.isDeclaration())
2877 continue;
2878 if (F.getMetadata("reqd_work_group_size"))
2880 SPIRV::OperandCategory::ExecutionModeOperand,
2881 SPIRV::ExecutionMode::LocalSize, ST);
2882 if (F.getFnAttribute("hlsl.numthreads").isValid()) {
2884 SPIRV::OperandCategory::ExecutionModeOperand,
2885 SPIRV::ExecutionMode::LocalSize, ST);
2886 }
2887 if (F.getFnAttribute("enable-maximal-reconvergence").getValueAsBool()) {
2888 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_maximal_reconvergence);
2889 }
2890 if (F.getMetadata("work_group_size_hint"))
2892 SPIRV::OperandCategory::ExecutionModeOperand,
2893 SPIRV::ExecutionMode::LocalSizeHint, ST);
2894 if (F.getMetadata("intel_reqd_sub_group_size") ||
2895 F.getMetadata("reqd_sub_group_size"))
2897 SPIRV::OperandCategory::ExecutionModeOperand,
2898 SPIRV::ExecutionMode::SubgroupSize, ST);
2899 if (F.getMetadata("max_work_group_size"))
2901 SPIRV::OperandCategory::ExecutionModeOperand,
2902 SPIRV::ExecutionMode::MaxWorkgroupSizeINTEL, ST);
2903 if (F.getMetadata("vec_type_hint"))
2905 SPIRV::OperandCategory::ExecutionModeOperand,
2906 SPIRV::ExecutionMode::VecTypeHint, ST);
2907
2908 if (F.hasOptNone()) {
2909 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_optnone)) {
2910 MAI.Reqs.addExtension(SPIRV::Extension::SPV_INTEL_optnone);
2911 MAI.Reqs.addCapability(SPIRV::Capability::OptNoneINTEL);
2912 } else if (ST.canUseExtension(SPIRV::Extension::SPV_EXT_optnone)) {
2913 MAI.Reqs.addExtension(SPIRV::Extension::SPV_EXT_optnone);
2914 MAI.Reqs.addCapability(SPIRV::Capability::OptNoneEXT);
2915 }
2916 }
2917 }
2918}
2919
2920static unsigned getFastMathFlags(const MachineInstr &I,
2921 const SPIRVSubtarget &ST) {
2922 unsigned Flags = SPIRV::FPFastMathMode::None;
2923 bool CanUseKHRFloatControls2 =
2924 ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2);
2925 if (I.getFlag(MachineInstr::MIFlag::FmNoNans))
2926 Flags |= SPIRV::FPFastMathMode::NotNaN;
2927 if (I.getFlag(MachineInstr::MIFlag::FmNoInfs))
2928 Flags |= SPIRV::FPFastMathMode::NotInf;
2929 if (I.getFlag(MachineInstr::MIFlag::FmNsz))
2930 Flags |= SPIRV::FPFastMathMode::NSZ;
2931 if (I.getFlag(MachineInstr::MIFlag::FmArcp))
2932 Flags |= SPIRV::FPFastMathMode::AllowRecip;
2933 if (I.getFlag(MachineInstr::MIFlag::FmContract) && CanUseKHRFloatControls2)
2934 Flags |= SPIRV::FPFastMathMode::AllowContract;
2935 if (I.getFlag(MachineInstr::MIFlag::FmReassoc)) {
2936 if (CanUseKHRFloatControls2)
2937 // LLVM reassoc maps to SPIRV transform, see
2938 // https://github.com/KhronosGroup/SPIRV-Registry/issues/326 for details.
2939 // Because we are enabling AllowTransform, we must enable AllowReassoc and
2940 // AllowContract too, as required by SPIRV spec. Also, we used to map
2941 // MIFlag::FmReassoc to FPFastMathMode::Fast, which now should instead by
2942 // replaced by turning all the other bits instead. Therefore, we're
2943 // enabling every bit here except None and Fast.
2944 Flags |= SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
2945 SPIRV::FPFastMathMode::NSZ | SPIRV::FPFastMathMode::AllowRecip |
2946 SPIRV::FPFastMathMode::AllowTransform |
2947 SPIRV::FPFastMathMode::AllowReassoc |
2948 SPIRV::FPFastMathMode::AllowContract;
2949 else
2950 Flags |= SPIRV::FPFastMathMode::Fast;
2951 }
2952
2953 if (CanUseKHRFloatControls2) {
2954 // Error out if SPIRV::FPFastMathMode::Fast is enabled.
2955 assert(!(Flags & SPIRV::FPFastMathMode::Fast) &&
2956 "SPIRV::FPFastMathMode::Fast is deprecated and should not be used "
2957 "anymore.");
2958
2959 // Error out if AllowTransform is enabled without AllowReassoc and
2960 // AllowContract.
2961 assert((!(Flags & SPIRV::FPFastMathMode::AllowTransform) ||
2962 ((Flags & SPIRV::FPFastMathMode::AllowReassoc &&
2963 Flags & SPIRV::FPFastMathMode::AllowContract))) &&
2964 "SPIRV::FPFastMathMode::AllowTransform requires AllowReassoc and "
2965 "AllowContract flags to be enabled as well.");
2966 }
2967
2968 return Flags;
2969}
2970
2972 if (ST.isKernel())
2973 return true;
2974 if (ST.getSPIRVVersion() < VersionTuple(1, 2))
2975 return false;
2976 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2);
2977}
2978
2980 MachineInstr &I, const SPIRVSubtarget &ST, const SPIRVInstrInfo &TII,
2982 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec) {
2983 bool Changed = false;
2984 // Insert after I so that the decorated register is defined before its use.
2985 MachineBasicBlock::iterator InsertPt = std::next(I.getIterator());
2986 auto Decorate = [&](SPIRV::Decoration::Decoration Dec,
2987 ArrayRef<uint32_t> DecArgs) {
2988 MachineIRBuilder MIRBuilder(*I.getParent(), InsertPt);
2989 MIRBuilder.setDebugLoc(I.getDebugLoc());
2990 buildOpDecorate(I.getOperand(0).getReg(), MIRBuilder, Dec, DecArgs);
2991 Changed = true;
2992 };
2993 if (TII.canUseIntegerWrapDecoration(I)) {
2994 if (I.getFlag(MachineInstr::MIFlag::NoSWrap) &&
2996 SPIRV::OperandCategory::DecorationOperand,
2997 SPIRV::Decoration::NoSignedWrap, ST, Reqs)
2998 .IsSatisfiable)
2999 Decorate(SPIRV::Decoration::NoSignedWrap, {});
3000 if (I.getFlag(MachineInstr::MIFlag::NoUWrap) &&
3002 SPIRV::OperandCategory::DecorationOperand,
3003 SPIRV::Decoration::NoUnsignedWrap, ST, Reqs)
3004 .IsSatisfiable)
3005 Decorate(SPIRV::Decoration::NoUnsignedWrap, {});
3006 }
3007 // In Kernel environments, FPFastMathMode on OpExtInst is valid per core
3008 // spec. For other instruction types, SPV_KHR_float_controls2 is required.
3009 bool CanUseFM =
3010 TII.canUseFastMathFlags(
3011 I, ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2)) ||
3012 (ST.isKernel() && I.getOpcode() == SPIRV::OpExtInst);
3013 if (!CanUseFM)
3014 return Changed;
3015
3016 unsigned FMFlags = getFastMathFlags(I, ST);
3017 if (FMFlags == SPIRV::FPFastMathMode::None) {
3018 // We also need to check if any FPFastMathDefault info was set for the
3019 // types used in this instruction.
3020 if (FPFastMathDefaultInfoVec.empty())
3021 return Changed;
3022
3023 // Use the first operand's FP type for arithmetic and comparisons,
3024 // and the result type for calls and extended instructions.
3025 SPIRVTypeInst FPType =
3026 I.getOpcode() == SPIRV::OpExtInst ||
3027 I.getOpcode() == SPIRV::OpFunctionCall
3028 ? I.getMF()->getRegInfo().getVRegDef(I.getOperand(1).getReg())
3029 : getRegType(I.getOperand(2).getReg(), *I.getMF(), GR);
3030 const Type *Ty = GR->getTypeForSPIRVType(FPType);
3031 Ty = Ty->isVectorTy() ? cast<VectorType>(Ty)->getElementType() : Ty;
3032
3033 // Match instruction type with the FPFastMathDefaultInfoVec.
3034 bool Emit = false;
3035 for (SPIRV::FPFastMathDefaultInfo &Elem : FPFastMathDefaultInfoVec) {
3036 if (Ty == Elem.Ty) {
3037 FMFlags = Elem.FastMathFlags;
3038 Emit = Elem.ContractionOff || Elem.SignedZeroInfNanPreserve ||
3039 Elem.FPFastMathDefault;
3040 break;
3041 }
3042 }
3043
3044 if (FMFlags == SPIRV::FPFastMathMode::None && !Emit)
3045 return Changed;
3046 }
3048 Decorate(SPIRV::Decoration::FPFastMathMode, {FMFlags});
3049 return Changed;
3050}
3051
3052static void addMBBNames(const Module &M, MachineFunctionGetter GetMF,
3054 for (const Function &F : M) {
3055 MachineFunction *MF = GetMF(F);
3056 if (!MF)
3057 continue;
3058 if (MF->getFunction()
3060 .isValid())
3061 continue;
3062 for (const auto &MBB : *MF) {
3063 if (!MBB.hasName() || MBB.empty())
3064 continue;
3065 MAI.MBBNames.emplace_back(MAI.getOrCreateMBBRegister(MBB), MBB.getName());
3066 }
3067 }
3068}
3069
3071 const Module &M,
3072 SPIRV::FPFastMathDefaultInfoMapTy &FPFastMathDefaultInfoMap,
3073 const Function *F) {
3074 auto it = FPFastMathDefaultInfoMap.find(F);
3075 if (it != FPFastMathDefaultInfoMap.end())
3076 return it->second;
3077
3078 // If the map does not contain the entry, create a new one. Initialize it to
3079 // contain all 3 elements sorted by bit width of target type: {half, float,
3080 // double}.
3081 SPIRV::FPFastMathDefaultInfoVector FPFastMathDefaultInfoVec;
3082 FPFastMathDefaultInfoVec.emplace_back(Type::getHalfTy(M.getContext()),
3083 SPIRV::FPFastMathMode::None);
3084 FPFastMathDefaultInfoVec.emplace_back(Type::getFloatTy(M.getContext()),
3085 SPIRV::FPFastMathMode::None);
3086 FPFastMathDefaultInfoVec.emplace_back(Type::getDoubleTy(M.getContext()),
3087 SPIRV::FPFastMathMode::None);
3088 return FPFastMathDefaultInfoMap[F] = std::move(FPFastMathDefaultInfoVec);
3089}
3090
3092 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec,
3093 const Type *Ty) {
3094 size_t BitWidth = Ty->getScalarSizeInBits();
3095 int Index =
3097 BitWidth);
3098 assert(Index >= 0 && Index < 3 &&
3099 "Expected FPFastMathDefaultInfo for half, float, or double");
3100 assert(FPFastMathDefaultInfoVec.size() == 3 &&
3101 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3102 return FPFastMathDefaultInfoVec[Index];
3103}
3104
3106 const Module &M,
3107 SPIRV::FPFastMathDefaultInfoMapTy &FPFastMathDefaultInfoMap,
3108 const SPIRVSubtarget &ST, const Function *OnlyF = nullptr) {
3109 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
3110 return;
3111
3112 // Store the FPFastMathDefaultInfo in the FPFastMathDefaultInfoMap.
3113 // We need the entry point (function) as the key, and the target
3114 // type and flags as the value.
3115 // We also need to check ContractionOff and SignedZeroInfNanPreserve
3116 // execution modes, as they are now deprecated and must be replaced
3117 // with FPFastMathDefaultInfo.
3118 auto Node = M.getNamedMetadata("spirv.ExecutionMode");
3119 if (!Node)
3120 return;
3121
3122 for (unsigned i = 0; i < Node->getNumOperands(); i++) {
3123 MDNode *MDN = cast<MDNode>(Node->getOperand(i));
3124 assert(MDN->getNumOperands() >= 2 && "Expected at least 2 operands");
3125 const Function *F = cast<Function>(
3126 cast<ConstantAsMetadata>(MDN->getOperand(0))->getValue());
3127 if (OnlyF && F != OnlyF)
3128 continue;
3129 const auto EM =
3131 cast<ConstantAsMetadata>(MDN->getOperand(1))->getValue())
3132 ->getZExtValue();
3133 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
3134 assert(MDN->getNumOperands() == 4 &&
3135 "Expected 4 operands for FPFastMathDefault");
3136
3137 const Type *T = cast<ValueAsMetadata>(MDN->getOperand(2))->getType();
3138 unsigned Flags =
3140 cast<ConstantAsMetadata>(MDN->getOperand(3))->getValue())
3141 ->getZExtValue();
3142 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3143 getOrCreateFPFastMathDefaultInfoVec(M, FPFastMathDefaultInfoMap, F);
3145 getFPFastMathDefaultInfo(FPFastMathDefaultInfoVec, T);
3146 Info.FastMathFlags = Flags;
3147 Info.FPFastMathDefault = true;
3148 } else if (EM == SPIRV::ExecutionMode::ContractionOff) {
3149 assert(MDN->getNumOperands() == 2 &&
3150 "Expected no operands for ContractionOff");
3151
3152 // We need to save this info for every possible FP type, i.e. {half,
3153 // float, double, fp128}.
3154 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3155 getOrCreateFPFastMathDefaultInfoVec(M, FPFastMathDefaultInfoMap, F);
3156 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3157 Info.ContractionOff = true;
3158 }
3159 } else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
3160 assert(MDN->getNumOperands() == 3 &&
3161 "Expected 1 operand for SignedZeroInfNanPreserve");
3162 unsigned TargetWidth =
3164 cast<ConstantAsMetadata>(MDN->getOperand(2))->getValue())
3165 ->getZExtValue();
3166 // We need to save this info only for the FP type with TargetWidth.
3167 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3168 getOrCreateFPFastMathDefaultInfoVec(M, FPFastMathDefaultInfoMap, F);
3171 assert(Index >= 0 && Index < 3 &&
3172 "Expected FPFastMathDefaultInfo for half, float, or double");
3173 assert(FPFastMathDefaultInfoVec.size() == 3 &&
3174 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3175 FPFastMathDefaultInfoVec[Index].SignedZeroInfNanPreserve = true;
3176 }
3177 }
3178}
3179
3183 : ST(&ST), GR(ST.getSPIRVGlobalRegistry()), TII(ST.getInstrInfo()),
3184 MAI(MAI), GetMF(GetMF) {}
3185
3187 setBaseInfo(M);
3188
3189 addMBBNames(M, GetMF, MAI);
3190 collectFPFastMathDefaults(M, MAI.FPFastMathDefaultInfoMap, *ST);
3191
3192 collectReqs(M, MAI, GetMF, *ST);
3193
3194 // Process type/const/global var/func decl instructions, number their
3195 // destination registers from 0 to N, collect Extensions and Capabilities.
3196 collectDeclarations(M);
3197
3198 // Number rest of registers from N+1 onwards.
3199 numberRegistersGlobally(M);
3200
3201 // Collect OpName, OpEntryPoint, OpDecorate etc, process other instructions.
3202 processOtherInstrs(M);
3203
3204 // If there are no entry points, we need the Linkage capability.
3205 if (MAI.MS[SPIRV::MB_EntryPoints].empty())
3206 MAI.Reqs.addCapability(SPIRV::Capability::Linkage);
3207
3208 // Set maximum ID used.
3209 GR->setBound(MAI.MaxID);
3210}
3211
3216
3218 SPIRVTargetMachine &TM =
3222 *TM.getSubtargetImpl(), MAI,
3223 [&MMI](const Function &F) { return MMI.getMachineFunction(F); })
3224 .run(M);
3225 return false;
3226}
3227
3228AnalysisKey SPIRVModuleAnalysis::Key;
3229
3232 const auto &TM = static_cast<const SPIRVTargetMachine &>(
3233 MAM.getResult<MachineModuleAnalysis>(M).getMMI().getTarget());
3235 MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
3236 Result MAI;
3237 SPIRVModuleAnalysisImpl(*TM.getSubtargetImpl(), MAI,
3238 [&FAM](const Function &F) -> MachineFunction * {
3239 MachineFunctionAnalysis::Result *MFA =
3240 FAM.getCachedResult<MachineFunctionAnalysis>(
3241 const_cast<Function &>(F));
3242 assert((MFA || F.isDeclaration()) &&
3243 "Missing MachineFunction for definition");
3244 return MFA ? &MFA->getMF() : nullptr;
3245 })
3246 .run(M);
3247 return MAI;
3248}
3249
3251 const auto &ST = MF.getSubtarget<SPIRVSubtarget>();
3252 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
3253 const SPIRVInstrInfo &TII = *ST.getInstrInfo();
3256 SPIRV::FPFastMathDefaultInfoMapTy FPFastMathDefaultInfoMap;
3257 const Function &F = MF.getFunction();
3258 collectFPFastMathDefaults(*F.getParent(), FPFastMathDefaultInfoMap, ST, &F);
3259 // Add decorations related to MI flags.
3260 bool Changed = false;
3261 for (auto &MBB : MF)
3262 for (auto &MI : make_early_inc_range(MBB))
3263 Changed |= handleMIFlagDecoration(MI, ST, TII, Reqs, GR,
3264 FPFastMathDefaultInfoMap[&F]);
3265 return Changed;
3266}
3267
3268namespace {
3269class SPIRVPrepareModuleAnalysisLegacy : public MachineFunctionPass {
3270public:
3271 static char ID;
3272 SPIRVPrepareModuleAnalysisLegacy() : MachineFunctionPass(ID) {}
3273 bool runOnMachineFunction(MachineFunction &MF) override {
3274 return prepareModuleAnalysis(MF);
3275 }
3276};
3277} // namespace
3278
3279char SPIRVPrepareModuleAnalysisLegacy::ID = 0;
3280
3281INITIALIZE_PASS(SPIRVPrepareModuleAnalysisLegacy,
3282 "spirv-prepare-module-analysis",
3283 "SPIRV prepare module analysis", false, false)
3284
3286 return new SPIRVPrepareModuleAnalysisLegacy();
3287}
3288
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
const AArch64Subtarget & Subtarget
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
ReachingDefInfo InstSet & ToRemove
MachineBasicBlock & MBB
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
#define DEBUG_TYPE
static Register UseReg(const MachineOperand &MO)
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define T
FunctionAnalysisManager FAM
ModuleAnalysisManager MAM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
MachineRegisterInfo & MRI
#define ATOM_FLT_REQ_EXT_MSG(ExtName)
static bool isFastMathModeAvailable(const SPIRVSubtarget &ST)
static void addMBBNames(const Module &M, MachineFunctionGetter GetMF, SPIRV::ModuleAnalysisInfo &MAI)
static void maybeAddScatterGatherReq(const MachineInstr &MI, SPIRV::RequirementHandler &Reqs, const SPIRVSubtarget &ST)
static void addImageOperandReqs(const MachineInstr &MI, SPIRV::RequirementHandler &Reqs, const SPIRVSubtarget &ST, unsigned OpIdx)
bool isStorageImage(MachineInstr *ImageInst)
bool isInputAttachment(MachineInstr *ImageInst)
static bool isBFloat16Type(SPIRVTypeInst TypeDef)
static bool handleMIFlagDecoration(MachineInstr &I, const SPIRVSubtarget &ST, const SPIRVInstrInfo &TII, SPIRV::RequirementHandler &Reqs, const SPIRVGlobalRegistry *GR, SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec)
bool isSampledImage(MachineInstr *ImageInst)
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::Hidden, cl::values(clEnumValN(SPIRV::Capability::Shader, "Shader", "SPIR-V Shader capability")))
static unsigned getInvokeOperandIdx(unsigned Opcode)
static SPIRV::FPFastMathDefaultInfo & getFPFastMathDefaultInfo(SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec, const Type *Ty)
static cl::opt< bool > SPVDumpDeps("spv-dump-deps", cl::desc("Dump MIR with SPIR-V dependencies info"), cl::init(false))
static void collectFPFastMathDefaults(const Module &M, SPIRV::FPFastMathDefaultInfoMapTy &FPFastMathDefaultInfoMap, const SPIRVSubtarget &ST, const Function *OnlyF=nullptr)
static void collectOtherInstr(MachineInstr &MI, SPIRV::ModuleAnalysisInfo &MAI, SPIRV::ModuleSectionType MSType, InstrTraces &IS, bool Append=true)
void addPrintfRequirements(const MachineInstr &MI, SPIRV::RequirementHandler &Reqs, const SPIRVSubtarget &ST)
static void addOpTypeImageReqs(const MachineInstr &MI, SPIRV::RequirementHandler &Reqs, const SPIRVSubtarget &ST)
static bool isImageTypeWithUnknownFormat(SPIRVTypeInst TypeInst)
bool isUniformTexelBuffer(MachineInstr *ImageInst)
bool isStorageTexelBuffer(MachineInstr *ImageInst)
static void AddAtomicFloatRequirements(const MachineInstr &MI, SPIRV::RequirementHandler &Reqs, const SPIRVSubtarget &ST)
bool isCombinedImageSampler(MachineInstr *SampledImageInst)
bool hasNonUniformDecoration(Register Reg, const MachineRegisterInfo &MRI)
const char * Msg
void addInstrRequirements(const MachineInstr &MI, SPIRV::ModuleAnalysisInfo &MAI, const SPIRVSubtarget &ST)
static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI, MachineFunctionGetter GetMF, const SPIRVSubtarget &ST)
static void addOpDecorateReqs(const MachineInstr &MI, unsigned DecIndex, SPIRV::RequirementHandler &Reqs, const SPIRVSubtarget &ST)
static InstrSignature instrToSignature(const MachineInstr &MI, SPIRV::ModuleAnalysisInfo &MAI, bool UseDefReg)
static void AddDotProductRequirements(const MachineInstr &MI, SPIRV::RequirementHandler &Reqs, const SPIRVSubtarget &ST)
static SPIRV::Requirements getSymbolicOperandRequirements(SPIRV::OperandCategory::OperandCategory Category, unsigned i, const SPIRVSubtarget &ST, SPIRV::RequirementHandler &Reqs)
static SPIRVTypeInst getRegType(Register Reg, const MachineFunction &MF, const SPIRVGlobalRegistry *GR)
static unsigned getMetadataUInt(MDNode *MdNode, unsigned OpIndex, unsigned DefaultVal=0)
static void addCoreInSPIRV13Capability(SPIRV::RequirementHandler &Reqs, const SPIRVSubtarget &ST, SPIRV::Capability::Capability Cap, SPIRV::Extension::Extension Ext)
void addOpAccessChainReqs(const MachineInstr &Instr, SPIRV::RequirementHandler &Handler, const SPIRVSubtarget &Subtarget)
static bool prepareModuleAnalysis(MachineFunction &MF)
static void appendDecorationsForReg(const MachineRegisterInfo &MRI, Register R, InstrSignature &Signature)
static SPIRV::FPFastMathDefaultInfoVector & getOrCreateFPFastMathDefaultInfoVec(const Module &M, SPIRV::FPFastMathDefaultInfoMapTy &FPFastMathDefaultInfoMap, const Function *F)
static void AddAtomicVectorFloatRequirements(const MachineInstr &MI, SPIRV::RequirementHandler &Reqs, const SPIRVSubtarget &ST)
static unsigned getFastMathFlags(const MachineInstr &I, const SPIRVSubtarget &ST)
#define SPIRV_BACKEND_SERVICE_FUN_NAME
Definition SPIRVUtils.h:558
This file contains some templates that are useful if you are working with the STL at all.
This file implements the StringSwitch template, which mimics a switch() statement whose cases are str...
#define LLVM_DEBUG(...)
Definition Debug.h:119
Target-Independent Code Generator Pass Configuration Options pass.
static Function * getFunction(FunctionType *Ty, const Twine &Name, Module *M)
Value * RHS
Value * LHS
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
bool isValid() const
Return true if the attribute is any kind of attribute.
Definition Attributes.h:262
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:44
Diagnostic information for unsupported feature in backend.
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:312
Attribute getFnAttribute(Attribute::AttrKind Kind) const
Return the attribute for the given attribute kind.
Definition Function.cpp:766
Wrapper class representing physical registers. Should be passed by value.
Definition MCRegister.h:41
constexpr bool isValid() const
Definition MCRegister.h:84
Metadata node.
Definition Metadata.h:1081
const MDOperand & getOperand(unsigned I) const
Definition Metadata.h:1437
unsigned getNumOperands() const
Return number of MDNode operands.
Definition Metadata.h:1443
Tracking metadata reference owned by Metadata.
Definition Metadata.h:902
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
Helper class to build MachineInstr.
void setDebugLoc(const DebugLoc &DL)
Set the debug location to DL for all the next build instructions.
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
An analysis that produces MachineModuleInfo for a module.
This class contains meta information specific to a module.
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.
static MachineOperand CreateImm(int64_t Val)
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,...
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
iterator_range< use_instr_iterator > use_instructions(Register Reg) const
LLVM_ABI LLVM_READONLY MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
iterator find(const KeyT &Key)
Definition MapVector.h:157
iterator end()
Definition MapVector.h:70
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
AnalysisType & getAnalysis() const
getAnalysis<AnalysisType>() - This function is used by subclasses to get to the analysis information ...
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isValid() const
Definition Register.h:112
unsigned getScalarOrVectorBitWidth(SPIRVTypeInst Type) const
SPIRVTypeInst getResultType(Register VReg, MachineFunction *MF=nullptr)
const Type * getTypeForSPIRVType(SPIRVTypeInst Ty) const
SPIRVTypeInst getSPIRVTypeForVReg(Register VReg, const MachineFunction *MF=nullptr) const
SPIRVModuleAnalysisImpl(const SPIRVSubtarget &ST, SPIRV::ModuleAnalysisInfo &MAI, MachineFunctionGetter GetMF)
SPIRV::ModuleAnalysisInfo Result
Result run(Module &M, ModuleAnalysisManager &MAM)
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
const SPIRVSubtarget * getSubtargetImpl() const
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition SmallSet.h:134
bool contains(const T &V) const
Check if the SmallSet contains the given element.
Definition SmallSet.h:229
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:184
reference emplace_back(ArgTypes &&... Args)
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.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
bool isVectorTy() const
True if this is an instance of VectorType.
Definition Type.h:283
static LLVM_ABI Type * getDoubleTy(LLVMContext &C)
Definition Type.cpp:277
static LLVM_ABI Type * getFloatTy(LLVMContext &C)
Definition Type.cpp:276
static LLVM_ABI Type * getHalfTy(LLVMContext &C)
Definition Type.cpp:274
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:348
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
MapVector< const Function *, FPFastMathDefaultInfoVector > FPFastMathDefaultInfoMapTy
SmallVector< const MachineInstr * > InstrList
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:679
This is an optimization pass for GlobalISel generic memory operations.
void stable_sort(R &&Range)
Definition STLExtras.h:2132
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:1755
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:643
SmallVector< size_t > InstrSignature
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:649
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
static void reportUnsupported(MachineIRBuilder &MIRBuilder, const Twine &Msg)
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, SPIRV::Decoration::Decoration Dec, ArrayRef< uint32_t > DecArgs, StringRef StrImm)
bool isVectorType(SPIRVTypeInst SPVTy)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
VersionTuple getSymbolicOperandMaxVersion(SPIRV::OperandCategory::OperandCategory Category, uint32_t Value)
function_ref< MachineFunction *(const Function &)> MachineFunctionGetter
void erase(Container &C, ValueType V)
Wrapper function to remove a value from a container:
Definition STLExtras.h:2216
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:209
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
FunctionPass * createSPIRVPrepareModuleAnalysisLegacyPass()
std::string getSymbolicOperandMnemonic(SPIRV::OperandCategory::OperandCategory Category, int32_t Value)
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
bool requiresLongVectorEXT(unsigned NumComponents, bool CanUseVector16=true)
Definition SPIRVUtils.h:513
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:559
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1963
SmallVector< SPIRV::Capability::Capability, 8 > CapabilityList
std::set< InstrSignature > InstrTraces
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition Hashing.h:307
std::map< SmallVector< size_t >, unsigned > InstrGRegsMap
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Definition Error.cpp:177
#define N
SmallSet< SPIRV::Capability::Capability, 4 > S
A special type used by analysis passes to provide an address that identifies that particular analysis...
Definition Analysis.h:29
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
bool runOnModule(Module &M) override
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
static size_t computeFPFastMathDefaultInfoVecIndex(size_t BitWidth)
Definition SPIRVUtils.h:149
void setSkipEmission(const MachineInstr *MI)
MCRegister getRegisterAlias(const MachineFunction *MF, Register Reg)
MCRegister getOrCreateMBBRegister(const MachineBasicBlock &MBB)
InstrList MS[NUM_MODULE_SECTIONS]
AddressingModel::AddressingModel Addr
SmallVector< std::pair< MCRegister, StringRef > > MBBNames
void checkSatisfiable(const SPIRVSubtarget &ST) const
void getAndAddRequirements(SPIRV::OperandCategory::OperandCategory Category, uint32_t i, const SPIRVSubtarget &ST)
void addRequirements(const Requirements &Req)
bool isCapabilityAvailable(Capability::Capability Cap) const
void removeCapabilityIf(const Capability::Capability ToRemove, const Capability::Capability IfPresent)
void addExtensions(const ExtensionList &ToAdd)
void addAvailableCaps(const CapabilityList &ToAdd)
void addExtension(Extension::Extension ToAdd)
void initAvailableCapabilities(const SPIRVSubtarget &ST)
void addCapability(Capability::Capability ToAdd)
void addCapabilities(const CapabilityList &ToAdd)
const std::optional< Capability::Capability > Cap