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 if (!ST.isShader()) {
1035 initAvailableCapabilitiesForOpenCL(ST);
1036 return;
1037 }
1038
1039 if (ST.isShader()) {
1040 initAvailableCapabilitiesForVulkan(ST);
1041 return;
1042 }
1043
1044 report_fatal_error("Unimplemented environment for SPIR-V generation.");
1045}
1046
1047void RequirementHandler::initAvailableCapabilitiesForOpenCL(
1048 const SPIRVSubtarget &ST) {
1049 // Add the min requirements for different OpenCL and SPIR-V versions.
1050 addAvailableCaps({Capability::Addresses, Capability::Float16Buffer,
1051 Capability::Kernel, Capability::Vector16,
1052 Capability::Groups, Capability::GenericPointer,
1053 Capability::StorageImageWriteWithoutFormat,
1054 Capability::StorageImageReadWithoutFormat});
1055 if (ST.hasOpenCLFullProfile())
1056 addAvailableCaps({Capability::Int64, Capability::Int64Atomics});
1057 if (ST.hasOpenCLImageSupport()) {
1058 addAvailableCaps({Capability::ImageBasic, Capability::LiteralSampler,
1059 Capability::Image1D, Capability::SampledBuffer,
1060 Capability::ImageBuffer});
1061 if (ST.isAtLeastOpenCLVer(VersionTuple(2, 0)))
1062 addAvailableCaps({Capability::ImageReadWrite});
1063 }
1064 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 1)) &&
1065 ST.isAtLeastOpenCLVer(VersionTuple(2, 2)))
1066 addAvailableCaps({Capability::SubgroupDispatch, Capability::PipeStorage});
1067 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 4)))
1068 addAvailableCaps({Capability::DenormPreserve, Capability::DenormFlushToZero,
1069 Capability::SignedZeroInfNanPreserve,
1070 Capability::RoundingModeRTE,
1071 Capability::RoundingModeRTZ});
1072 // TODO: verify if this needs some checks.
1073 addAvailableCaps({Capability::Float16, Capability::Float64});
1074
1075 // TODO: add OpenCL extensions.
1076}
1077
1078void RequirementHandler::initAvailableCapabilitiesForVulkan(
1079 const SPIRVSubtarget &ST) {
1080
1081 // Core in Vulkan 1.1 and earlier.
1082 addAvailableCaps({Capability::Int64,
1083 Capability::Geometry,
1084 Capability::Float16,
1085 Capability::Float64,
1086 Capability::GroupNonUniform,
1087 Capability::Image1D,
1088 Capability::SampledBuffer,
1089 Capability::ImageBuffer,
1090 Capability::UniformBufferArrayDynamicIndexing,
1091 Capability::SampledImageArrayDynamicIndexing,
1092 Capability::StorageBufferArrayDynamicIndexing,
1093 Capability::StorageImageArrayDynamicIndexing,
1094 Capability::DerivativeControl,
1095 Capability::SampleRateShading,
1096 Capability::MinLod,
1097 Capability::ImageQuery,
1098 Capability::ImageGatherExtended,
1099 Capability::Addresses,
1100 Capability::VulkanMemoryModelKHR,
1101 Capability::StorageImageExtendedFormats,
1102 Capability::StorageImageMultisample,
1103 Capability::ImageMSArray});
1104
1105 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 3)) ||
1106 ST.canUseExtension(Extension::SPV_KHR_variable_pointers))
1107 addAvailableCaps({Capability::VariablePointersStorageBuffer,
1108 Capability::VariablePointers});
1109
1110 // Became core in Vulkan 1.1.
1111 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 3)))
1112 addAvailableCaps({Capability::DrawParameters, Capability::MultiView});
1113
1114 // Became core in Vulkan 1.2
1115 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 5))) {
1117 {Capability::Int64Atomics, Capability::ShaderNonUniformEXT,
1118 Capability::RuntimeDescriptorArrayEXT,
1119 Capability::InputAttachmentArrayDynamicIndexingEXT,
1120 Capability::UniformTexelBufferArrayDynamicIndexingEXT,
1121 Capability::StorageTexelBufferArrayDynamicIndexingEXT,
1122 Capability::UniformBufferArrayNonUniformIndexingEXT,
1123 Capability::SampledImageArrayNonUniformIndexingEXT,
1124 Capability::StorageBufferArrayNonUniformIndexingEXT,
1125 Capability::StorageImageArrayNonUniformIndexingEXT,
1126 Capability::InputAttachmentArrayNonUniformIndexingEXT,
1127 Capability::UniformTexelBufferArrayNonUniformIndexingEXT,
1128 Capability::StorageTexelBufferArrayNonUniformIndexingEXT});
1129 }
1130
1131 // Became core in Vulkan 1.3
1132 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 6)))
1133 addAvailableCaps({Capability::StorageImageWriteWithoutFormat,
1134 Capability::StorageImageReadWithoutFormat});
1135}
1136
1137} // namespace SPIRV
1138} // namespace llvm
1139
1140// Add a capability that became core in SPIR-V 1.3. Earlier versions require
1141// the extension that introduced it.
1143 const SPIRVSubtarget &ST,
1144 SPIRV::Capability::Capability Cap,
1145 SPIRV::Extension::Extension Ext) {
1146 Reqs.addCapability(Cap);
1147 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 3)))
1148 return;
1149 if (!ST.canUseExtension(Ext))
1151 Twine("capability ") +
1153 SPIRV::OperandCategory::CapabilityOperand, Cap) +
1154 " requires SPIR-V 1.3 or the following SPIR-V extension: " +
1155 getSymbolicOperandMnemonic(SPIRV::OperandCategory::ExtensionOperand,
1156 Ext),
1157 false);
1158 Reqs.addExtension(Ext);
1159}
1160
1161// Add the required capabilities from a decoration instruction (including
1162// BuiltIns).
1163static void addOpDecorateReqs(const MachineInstr &MI, unsigned DecIndex,
1165 const SPIRVSubtarget &ST) {
1166 int64_t DecOp = MI.getOperand(DecIndex).getImm();
1167 auto Dec = static_cast<SPIRV::Decoration::Decoration>(DecOp);
1169 SPIRV::OperandCategory::DecorationOperand, Dec, ST, Reqs));
1170
1171 if (Dec == SPIRV::Decoration::BuiltIn) {
1172 int64_t BuiltInOp = MI.getOperand(DecIndex + 1).getImm();
1173 auto BuiltIn = static_cast<SPIRV::BuiltIn::BuiltIn>(BuiltInOp);
1174 if ((BuiltIn == SPIRV::BuiltIn::BaryCoordKHR ||
1175 BuiltIn == SPIRV::BuiltIn::BaryCoordNoPerspKHR) &&
1176 !ST.canUseExtension(
1177 SPIRV::Extension::SPV_KHR_fragment_shader_barycentric))
1179 "Barycentric built-ins require the following SPIR-V extension: "
1180 "SPV_KHR_fragment_shader_barycentric",
1181 false);
1182 switch (BuiltIn) {
1183 case SPIRV::BuiltIn::BaseVertex:
1184 case SPIRV::BuiltIn::BaseInstance:
1186 Reqs, ST, SPIRV::Capability::DrawParameters,
1187 SPIRV::Extension::SPV_KHR_shader_draw_parameters);
1188 break;
1189 case SPIRV::BuiltIn::ViewIndex:
1190 addCoreInSPIRV13Capability(Reqs, ST, SPIRV::Capability::MultiView,
1191 SPIRV::Extension::SPV_KHR_multiview);
1192 break;
1193 default:
1195 SPIRV::OperandCategory::BuiltInOperand, BuiltIn, ST, Reqs));
1196 break;
1197 }
1198 } else if (Dec == SPIRV::Decoration::LinkageAttributes) {
1199 int64_t LinkageOp = MI.getOperand(MI.getNumOperands() - 1).getImm();
1200 SPIRV::LinkageType::LinkageType LnkType =
1201 static_cast<SPIRV::LinkageType::LinkageType>(LinkageOp);
1202 if (LnkType == SPIRV::LinkageType::LinkOnceODR)
1203 Reqs.addExtension(SPIRV::Extension::SPV_KHR_linkonce_odr);
1204 else if (LnkType == SPIRV::LinkageType::WeakAMD) {
1205 Reqs.addExtension(SPIRV::Extension::SPV_AMD_weak_linkage);
1206 Reqs.addCapability(SPIRV::Capability::WeakLinkageAMD);
1207 }
1208 } else if (Dec == SPIRV::Decoration::CacheControlLoadINTEL ||
1209 Dec == SPIRV::Decoration::CacheControlStoreINTEL) {
1210 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_cache_controls);
1211 } else if (Dec == SPIRV::Decoration::HostAccessINTEL) {
1212 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_global_variable_host_access);
1213 } else if (Dec == SPIRV::Decoration::InitModeINTEL ||
1214 Dec == SPIRV::Decoration::ImplementInRegisterMapINTEL) {
1215 Reqs.addExtension(
1216 SPIRV::Extension::SPV_INTEL_global_variable_fpga_decorations);
1217 } else if (Dec == SPIRV::Decoration::NonUniformEXT) {
1218 Reqs.addRequirements(SPIRV::Capability::ShaderNonUniformEXT);
1219 } else if (Dec == SPIRV::Decoration::FPMaxErrorDecorationINTEL) {
1220 Reqs.addRequirements(SPIRV::Capability::FPMaxErrorINTEL);
1221 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_fp_max_error);
1222 } else if (Dec == SPIRV::Decoration::FPFastMathMode) {
1223 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2)) {
1224 Reqs.addRequirements(SPIRV::Capability::FloatControls2);
1225 Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls2);
1226 }
1227 }
1228}
1229
1230// Add requirements for image handling.
1233 const SPIRVSubtarget &ST) {
1234 assert(MI.getNumOperands() >= 8 && "Insufficient operands for OpTypeImage");
1235 // The operand indices used here are based on the OpTypeImage layout, which
1236 // the MachineInstr follows as well.
1237 int64_t ImgFormatOp = MI.getOperand(7).getImm();
1238 auto ImgFormat = static_cast<SPIRV::ImageFormat::ImageFormat>(ImgFormatOp);
1239 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ImageFormatOperand,
1240 ImgFormat, ST);
1241
1242 bool IsArrayed = MI.getOperand(4).getImm() == 1;
1243 bool IsMultisampled = MI.getOperand(5).getImm() == 1;
1244 bool NoSampler = MI.getOperand(6).getImm() == 2;
1245 // Add dimension requirements.
1246 assert(MI.getOperand(2).isImm());
1247 switch (MI.getOperand(2).getImm()) {
1248 case SPIRV::Dim::DIM_1D:
1249 Reqs.addRequirements(NoSampler ? SPIRV::Capability::Image1D
1250 : SPIRV::Capability::Sampled1D);
1251 break;
1252 case SPIRV::Dim::DIM_2D:
1253 if (IsMultisampled && NoSampler)
1254 Reqs.addRequirements(SPIRV::Capability::StorageImageMultisample);
1255 if (IsMultisampled && IsArrayed)
1256 Reqs.addRequirements(SPIRV::Capability::ImageMSArray);
1257 break;
1258 case SPIRV::Dim::DIM_3D:
1259 break;
1260 case SPIRV::Dim::DIM_Cube:
1261 Reqs.addRequirements(SPIRV::Capability::Shader);
1262 if (IsArrayed)
1263 Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageCubeArray
1264 : SPIRV::Capability::SampledCubeArray);
1265 break;
1266 case SPIRV::Dim::DIM_Rect:
1267 Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageRect
1268 : SPIRV::Capability::SampledRect);
1269 break;
1270 case SPIRV::Dim::DIM_Buffer:
1271 Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageBuffer
1272 : SPIRV::Capability::SampledBuffer);
1273 break;
1274 case SPIRV::Dim::DIM_SubpassData:
1275 Reqs.addRequirements(SPIRV::Capability::InputAttachment);
1276 break;
1277 }
1278
1279 // Has optional access qualifier.
1280 if (!ST.isShader()) {
1281 if (MI.getNumOperands() > 8 &&
1282 MI.getOperand(8).getImm() == SPIRV::AccessQualifier::ReadWrite)
1283 Reqs.addRequirements(SPIRV::Capability::ImageReadWrite);
1284 else
1285 Reqs.addRequirements(SPIRV::Capability::ImageBasic);
1286 }
1287}
1288
1289static bool isBFloat16Type(SPIRVTypeInst TypeDef) {
1290 return TypeDef && TypeDef->getNumOperands() == 3 &&
1291 TypeDef->getOpcode() == SPIRV::OpTypeFloat &&
1292 TypeDef->getOperand(1).getImm() == 16 &&
1293 TypeDef->getOperand(2).getImm() == SPIRV::FPEncoding::BFloat16KHR;
1294}
1295
1296// Registers created after isel (e.g. by MachineCSE) may lack registry entries.
1297// Fall back to the defining instruction's result type.
1299 const SPIRVGlobalRegistry *GR) {
1300 if (SPIRVTypeInst Ty = GR->getSPIRVTypeForVReg(Reg, &MF))
1301 return Ty;
1302 const MachineRegisterInfo &MRI = MF.getRegInfo();
1303 return MRI.getVRegDef(MRI.getVRegDef(Reg)->getOperand(1).getReg());
1304}
1305
1306// Add requirements for handling atomic float instructions
1307#define ATOM_FLT_REQ_EXT_MSG(ExtName) \
1308 "The atomic float instruction requires the following SPIR-V " \
1309 "extension: SPV_EXT_shader_atomic_float" ExtName
1312 const SPIRVSubtarget &ST) {
1313 SPIRVTypeInst VecTypeDef =
1314 MI.getMF()->getRegInfo().getVRegDef(MI.getOperand(1).getReg());
1315
1316 const unsigned Rank = VecTypeDef->getOperand(2).getImm();
1317 if (Rank != 2 && Rank != 4)
1318 reportFatalUsageError("Result type of an atomic vector float instruction "
1319 "must be a 2-component or 4 component vector");
1320
1321 SPIRVTypeInst EltTypeDef =
1322 MI.getMF()->getRegInfo().getVRegDef(VecTypeDef->getOperand(1).getReg());
1323
1324 if (EltTypeDef->getOpcode() != SPIRV::OpTypeFloat ||
1325 EltTypeDef->getOperand(1).getImm() != 16)
1327 "The element type for the result type of an atomic vector float "
1328 "instruction must be a 16-bit floating-point scalar");
1329
1330 // The extension is defined for fp16, but the AMD target lets a bf16 vector
1331 // use the same instruction so it can lower to a packed bf16 atomic.
1332 if (isBFloat16Type(EltTypeDef) &&
1333 ST.getTargetTriple().getVendor() != Triple::AMD)
1335 "The element type for the result type of an atomic vector float "
1336 "instruction cannot be a bfloat16 scalar");
1337 if (!ST.canUseExtension(SPIRV::Extension::SPV_NV_shader_atomic_fp16_vector))
1339 "The atomic float16 vector instruction requires the following SPIR-V "
1340 "extension: SPV_NV_shader_atomic_fp16_vector");
1341
1342 Reqs.addExtension(SPIRV::Extension::SPV_NV_shader_atomic_fp16_vector);
1343 Reqs.addCapability(SPIRV::Capability::AtomicFloat16VectorNV);
1344}
1345
1348 const SPIRVSubtarget &ST) {
1349 assert(MI.getOperand(1).isReg() &&
1350 "Expect register operand in atomic float instruction");
1351 Register TypeReg = MI.getOperand(1).getReg();
1352 SPIRVTypeInst TypeDef = MI.getMF()->getRegInfo().getVRegDef(TypeReg);
1353
1354 if (isVectorType(TypeDef))
1355 return AddAtomicVectorFloatRequirements(MI, Reqs, ST);
1356
1357 if (TypeDef->getOpcode() != SPIRV::OpTypeFloat)
1358 report_fatal_error("Result type of an atomic float instruction must be a "
1359 "floating-point type scalar");
1360
1361 unsigned BitWidth = TypeDef->getOperand(1).getImm();
1362 unsigned Op = MI.getOpcode();
1363 if (Op == SPIRV::OpAtomicFAddEXT) {
1364 if (!ST.canUseExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_add))
1366 Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_add);
1367 switch (BitWidth) {
1368 case 16:
1369 if (isBFloat16Type(TypeDef)) {
1370 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics))
1372 "The atomic bfloat16 instruction requires the following SPIR-V "
1373 "extension: SPV_INTEL_16bit_atomics",
1374 false);
1375 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics);
1376 Reqs.addCapability(SPIRV::Capability::AtomicBFloat16AddINTEL);
1377 } else {
1378 if (!ST.canUseExtension(
1379 SPIRV::Extension::SPV_EXT_shader_atomic_float16_add))
1380 report_fatal_error(ATOM_FLT_REQ_EXT_MSG("16_add"), false);
1381 Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float16_add);
1382 Reqs.addCapability(SPIRV::Capability::AtomicFloat16AddEXT);
1383 }
1384 break;
1385 case 32:
1386 Reqs.addCapability(SPIRV::Capability::AtomicFloat32AddEXT);
1387 break;
1388 case 64:
1389 Reqs.addCapability(SPIRV::Capability::AtomicFloat64AddEXT);
1390 break;
1391 default:
1393 "Unexpected floating-point type width in atomic float instruction");
1394 }
1395 } else {
1396 if (!ST.canUseExtension(
1397 SPIRV::Extension::SPV_EXT_shader_atomic_float_min_max))
1398 report_fatal_error(ATOM_FLT_REQ_EXT_MSG("_min_max"), false);
1399 Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_min_max);
1400 switch (BitWidth) {
1401 case 16:
1402 if (isBFloat16Type(TypeDef)) {
1403 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics))
1405 "The atomic bfloat16 instruction requires the following SPIR-V "
1406 "extension: SPV_INTEL_16bit_atomics",
1407 false);
1408 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics);
1409 Reqs.addCapability(SPIRV::Capability::AtomicBFloat16MinMaxINTEL);
1410 } else {
1411 Reqs.addCapability(SPIRV::Capability::AtomicFloat16MinMaxEXT);
1412 }
1413 break;
1414 case 32:
1415 Reqs.addCapability(SPIRV::Capability::AtomicFloat32MinMaxEXT);
1416 break;
1417 case 64:
1418 Reqs.addCapability(SPIRV::Capability::AtomicFloat64MinMaxEXT);
1419 break;
1420 default:
1422 "Unexpected floating-point type width in atomic float instruction");
1423 }
1424 }
1425}
1426
1428 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1429 return false;
1430 uint32_t Dim = ImageInst->getOperand(2).getImm();
1431 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1432 return Dim == SPIRV::Dim::DIM_Buffer && Sampled == 1;
1433}
1434
1436 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1437 return false;
1438 uint32_t Dim = ImageInst->getOperand(2).getImm();
1439 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1440 return Dim == SPIRV::Dim::DIM_Buffer && Sampled == 2;
1441}
1442
1444 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1445 return false;
1446 uint32_t Dim = ImageInst->getOperand(2).getImm();
1447 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1448 return Dim != SPIRV::Dim::DIM_Buffer && Sampled == 1;
1449}
1450
1452 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1453 return false;
1454 uint32_t Dim = ImageInst->getOperand(2).getImm();
1455 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1456 return Dim == SPIRV::Dim::DIM_SubpassData && Sampled == 2;
1457}
1458
1460 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1461 return false;
1462 uint32_t Dim = ImageInst->getOperand(2).getImm();
1463 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1464 return Dim != SPIRV::Dim::DIM_Buffer && Sampled == 2;
1465}
1466
1467bool isCombinedImageSampler(MachineInstr *SampledImageInst) {
1468 if (SampledImageInst->getOpcode() != SPIRV::OpTypeSampledImage)
1469 return false;
1470
1471 const MachineRegisterInfo &MRI = SampledImageInst->getMF()->getRegInfo();
1472 Register ImageReg = SampledImageInst->getOperand(1).getReg();
1473 auto *ImageInst = MRI.getUniqueVRegDef(ImageReg);
1474 return isSampledImage(ImageInst);
1475}
1476
1478 for (const auto &MI : MRI.reg_instructions(Reg)) {
1479 if (MI.getOpcode() != SPIRV::OpDecorate)
1480 continue;
1481
1482 uint32_t Dec = MI.getOperand(1).getImm();
1483 if (Dec == SPIRV::Decoration::NonUniformEXT)
1484 return true;
1485 }
1486 return false;
1487}
1488
1491 const SPIRVSubtarget &Subtarget) {
1492 const MachineRegisterInfo &MRI = Instr.getMF()->getRegInfo();
1493 // Get the result type. If it is an image type, then the shader uses
1494 // descriptor indexing. The appropriate capabilities will be added based
1495 // on the specifics of the image.
1496 Register ResTypeReg = Instr.getOperand(1).getReg();
1497 MachineInstr *ResTypeInst = MRI.getUniqueVRegDef(ResTypeReg);
1498
1499 assert(ResTypeInst->getOpcode() == SPIRV::OpTypePointer);
1500 uint32_t StorageClass = ResTypeInst->getOperand(1).getImm();
1501 if (StorageClass != SPIRV::StorageClass::StorageClass::UniformConstant &&
1502 StorageClass != SPIRV::StorageClass::StorageClass::Uniform &&
1503 StorageClass != SPIRV::StorageClass::StorageClass::StorageBuffer) {
1504 return;
1505 }
1506
1507 bool IsNonUniform =
1508 hasNonUniformDecoration(Instr.getOperand(0).getReg(), MRI);
1509
1510 auto FirstIndexReg = Instr.getOperand(3).getReg();
1511 bool FirstIndexIsConstant =
1512 Subtarget.getInstrInfo()->isConstantInstr(*MRI.getVRegDef(FirstIndexReg));
1513
1514 if (StorageClass == SPIRV::StorageClass::StorageClass::StorageBuffer) {
1515 if (IsNonUniform)
1516 Handler.addRequirements(
1517 SPIRV::Capability::StorageBufferArrayNonUniformIndexingEXT);
1518 else if (!FirstIndexIsConstant)
1519 Handler.addRequirements(
1520 SPIRV::Capability::StorageBufferArrayDynamicIndexing);
1521 return;
1522 }
1523
1524 Register PointeeTypeReg = ResTypeInst->getOperand(2).getReg();
1525 MachineInstr *PointeeType = MRI.getUniqueVRegDef(PointeeTypeReg);
1526 if (PointeeType->getOpcode() != SPIRV::OpTypeImage &&
1527 PointeeType->getOpcode() != SPIRV::OpTypeSampledImage &&
1528 PointeeType->getOpcode() != SPIRV::OpTypeSampler) {
1529 return;
1530 }
1531
1532 if (isUniformTexelBuffer(PointeeType)) {
1533 if (IsNonUniform)
1534 Handler.addRequirements(
1535 SPIRV::Capability::UniformTexelBufferArrayNonUniformIndexingEXT);
1536 else if (!FirstIndexIsConstant)
1537 Handler.addRequirements(
1538 SPIRV::Capability::UniformTexelBufferArrayDynamicIndexingEXT);
1539 } else if (isInputAttachment(PointeeType)) {
1540 if (IsNonUniform)
1541 Handler.addRequirements(
1542 SPIRV::Capability::InputAttachmentArrayNonUniformIndexingEXT);
1543 else if (!FirstIndexIsConstant)
1544 Handler.addRequirements(
1545 SPIRV::Capability::InputAttachmentArrayDynamicIndexingEXT);
1546 } else if (isStorageTexelBuffer(PointeeType)) {
1547 if (IsNonUniform)
1548 Handler.addRequirements(
1549 SPIRV::Capability::StorageTexelBufferArrayNonUniformIndexingEXT);
1550 else if (!FirstIndexIsConstant)
1551 Handler.addRequirements(
1552 SPIRV::Capability::StorageTexelBufferArrayDynamicIndexingEXT);
1553 } else if (isSampledImage(PointeeType) ||
1554 isCombinedImageSampler(PointeeType) ||
1555 PointeeType->getOpcode() == SPIRV::OpTypeSampler) {
1556 if (IsNonUniform)
1557 Handler.addRequirements(
1558 SPIRV::Capability::SampledImageArrayNonUniformIndexingEXT);
1559 else if (!FirstIndexIsConstant)
1560 Handler.addRequirements(
1561 SPIRV::Capability::SampledImageArrayDynamicIndexing);
1562 } else if (isStorageImage(PointeeType)) {
1563 if (IsNonUniform)
1564 Handler.addRequirements(
1565 SPIRV::Capability::StorageImageArrayNonUniformIndexingEXT);
1566 else if (!FirstIndexIsConstant)
1567 Handler.addRequirements(
1568 SPIRV::Capability::StorageImageArrayDynamicIndexing);
1569 }
1570}
1571
1573 if (TypeInst->getOpcode() != SPIRV::OpTypeImage)
1574 return false;
1575 assert(TypeInst->getOperand(7).isImm() && "The image format must be an imm.");
1576 return TypeInst->getOperand(7).getImm() == 0;
1577}
1578
1581 const SPIRVSubtarget &ST) {
1582 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product))
1583 Reqs.addExtension(SPIRV::Extension::SPV_KHR_integer_dot_product);
1584 Reqs.addCapability(SPIRV::Capability::DotProduct);
1585
1586 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1587 assert(MI.getOperand(2).isReg() && "Unexpected operand in dot");
1588 SPIRVTypeInst TypeDef = getRegType(MI.getOperand(2).getReg(), *MI.getMF(),
1589 ST.getSPIRVGlobalRegistry());
1590 assert(TypeDef && "Unexpected type instruction for dot input");
1591 if (TypeDef->getOpcode() == SPIRV::OpTypeInt) {
1592 assert(TypeDef->getOperand(1).getImm() == 32);
1593 Reqs.addCapability(SPIRV::Capability::DotProductInput4x8BitPacked);
1594 } else if (isVectorType(TypeDef)) {
1595 SPIRVTypeInst ScalarTypeDef =
1596 MRI.getVRegDef(TypeDef->getOperand(1).getReg());
1597 assert(ScalarTypeDef->getOpcode() == SPIRV::OpTypeInt);
1598 if (ScalarTypeDef->getOperand(1).getImm() == 8) {
1599 assert(TypeDef->getOperand(2).getImm() == 4 &&
1600 "Dot operand of 8-bit integer type requires 4 components");
1601 Reqs.addCapability(SPIRV::Capability::DotProductInput4x8Bit);
1602 } else {
1603 Reqs.addCapability(SPIRV::Capability::DotProductInputAll);
1604 }
1605 }
1606}
1607
1610 const SPIRVSubtarget &ST) {
1611 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
1612 SPIRVTypeInst PtrType =
1613 GR->getSPIRVTypeForVReg(MI.getOperand(4).getReg(), MI.getMF());
1614 if (PtrType) {
1615 MachineOperand ASOp = PtrType->getOperand(1);
1616 if (ASOp.isImm()) {
1617 unsigned AddrSpace = ASOp.getImm();
1618 if (AddrSpace != SPIRV::StorageClass::UniformConstant) {
1619 if (!ST.canUseExtension(
1621 SPV_EXT_relaxed_printf_string_address_space)) {
1622 report_fatal_error("SPV_EXT_relaxed_printf_string_address_space is "
1623 "required because printf uses a format string not "
1624 "in constant address space.",
1625 false);
1626 }
1627 Reqs.addExtension(
1628 SPIRV::Extension::SPV_EXT_relaxed_printf_string_address_space);
1629 }
1630 }
1631 }
1632}
1633
1636 const SPIRVSubtarget &ST, unsigned OpIdx) {
1637 if (MI.getNumOperands() <= OpIdx)
1638 return;
1639 uint32_t Mask = MI.getOperand(OpIdx).getImm();
1640 for (uint32_t I = 0; I < 32; ++I)
1641 if (Mask & (1U << I))
1642 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ImageOperandOperand,
1643 1U << I, ST);
1644}
1645
1646static inline void maybeAddScatterGatherReq(const MachineInstr &MI,
1648 const SPIRVSubtarget &ST) {
1649 assert(MI.getOperand(1).isReg());
1650 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1651 SPIRVTypeInst ElemTypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
1652 if (ElemTypeDef->getOpcode() == SPIRV::OpTypePointer &&
1653 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
1654 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_masked_gather_scatter);
1655 Reqs.addCapability(SPIRV::Capability::MaskedGatherScatterINTEL);
1656 }
1657}
1658
1661 const SPIRVSubtarget &ST) {
1662 SPIRV::RequirementHandler &Reqs = MAI.Reqs;
1663 unsigned Op = MI.getOpcode();
1664 switch (Op) {
1665 case SPIRV::OpMemoryModel: {
1666 int64_t Addr = MI.getOperand(0).getImm();
1667 Reqs.getAndAddRequirements(SPIRV::OperandCategory::AddressingModelOperand,
1668 Addr, ST);
1669 int64_t Mem = MI.getOperand(1).getImm();
1670 Reqs.getAndAddRequirements(SPIRV::OperandCategory::MemoryModelOperand, Mem,
1671 ST);
1672 break;
1673 }
1674 case SPIRV::OpEntryPoint: {
1675 int64_t Exe = MI.getOperand(0).getImm();
1676 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ExecutionModelOperand,
1677 Exe, ST);
1678 break;
1679 }
1680 case SPIRV::OpExecutionMode:
1681 case SPIRV::OpExecutionModeId: {
1682 int64_t Exe = MI.getOperand(1).getImm();
1683 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ExecutionModeOperand,
1684 Exe, ST);
1685 break;
1686 }
1687 case SPIRV::OpTypeMatrix:
1688 Reqs.addCapability(SPIRV::Capability::Matrix);
1689 break;
1690 case SPIRV::OpTypeInt: {
1691 unsigned BitWidth = MI.getOperand(1).getImm();
1692 if (BitWidth == 64)
1693 Reqs.addCapability(SPIRV::Capability::Int64);
1694 else if (BitWidth == 16)
1695 Reqs.addCapability(SPIRV::Capability::Int16);
1696 else if (BitWidth == 8)
1697 Reqs.addCapability(SPIRV::Capability::Int8);
1698 else if (BitWidth == 4 &&
1699 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_int4)) {
1700 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_int4);
1701 Reqs.addCapability(SPIRV::Capability::Int4TypeINTEL);
1702 } else if (BitWidth != 32) {
1703 if (!ST.canUseExtension(
1704 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers))
1706 "OpTypeInt type with a width other than 8, 16, 32 or 64 bits "
1707 "requires the following SPIR-V extension: "
1708 "SPV_ALTERA_arbitrary_precision_integers");
1709 Reqs.addExtension(
1710 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers);
1711 Reqs.addCapability(SPIRV::Capability::ArbitraryPrecisionIntegersALTERA);
1712 }
1713 break;
1714 }
1715 case SPIRV::OpDot: {
1716 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1717 SPIRVTypeInst TypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
1718 if (isBFloat16Type(TypeDef))
1719 Reqs.addCapability(SPIRV::Capability::BFloat16DotProductKHR);
1720 break;
1721 }
1722 case SPIRV::OpTypeFloat: {
1723 unsigned BitWidth = MI.getOperand(1).getImm();
1724 if (BitWidth == 64)
1725 Reqs.addCapability(SPIRV::Capability::Float64);
1726 else if (BitWidth == 16) {
1727 if (isBFloat16Type(&MI)) {
1728 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_bfloat16))
1729 report_fatal_error("OpTypeFloat type with bfloat requires the "
1730 "following SPIR-V extension: SPV_KHR_bfloat16",
1731 false);
1732 Reqs.addExtension(SPIRV::Extension::SPV_KHR_bfloat16);
1733 Reqs.addCapability(SPIRV::Capability::BFloat16TypeKHR);
1734 } else {
1735 Reqs.addCapability(SPIRV::Capability::Float16);
1736 }
1737 }
1738 break;
1739 }
1740 case SPIRV::OpTypeVector: {
1741 unsigned NumComponents = MI.getOperand(2).getImm();
1742 if (NumComponents == 8 || NumComponents == 16)
1743 Reqs.addCapability(SPIRV::Capability::Vector16);
1744 else if (requiresLongVectorEXT(NumComponents))
1745 // Such widths are only expressible as OpTypeVectorIdEXT.
1747 "OpTypeVector with " + Twine(NumComponents) +
1748 " components requires the following SPIR-V extension: "
1749 "SPV_EXT_long_vector");
1750
1751 maybeAddScatterGatherReq(MI, Reqs, ST);
1752 break;
1753 }
1754 case SPIRV::OpTypeVectorIdEXT: {
1755 if (!ST.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector))
1756 reportFatalUsageError("OpTypeVectorIdEXT requires the following SPIR-V "
1757 "extension: SPV_EXT_long_vector extension");
1758 Reqs.addExtension(SPIRV::Extension::SPV_EXT_long_vector);
1759 Reqs.addCapability(SPIRV::Capability::LongVectorEXT);
1760 maybeAddScatterGatherReq(MI, Reqs, ST);
1761 break;
1762 }
1763 case SPIRV::OpTypePointer: {
1764 auto SC = MI.getOperand(1).getImm();
1765 Reqs.getAndAddRequirements(SPIRV::OperandCategory::StorageClassOperand, SC,
1766 ST);
1767 // If it's a type of pointer to float16 targeting OpenCL, add Float16Buffer
1768 // capability.
1769 if (ST.isShader())
1770 break;
1771 assert(MI.getOperand(2).isReg());
1772 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1773 SPIRVTypeInst TypeDef = MRI.getVRegDef(MI.getOperand(2).getReg());
1774 if ((TypeDef->getNumOperands() == 2) &&
1775 (TypeDef->getOpcode() == SPIRV::OpTypeFloat) &&
1776 (TypeDef->getOperand(1).getImm() == 16))
1777 Reqs.addCapability(SPIRV::Capability::Float16Buffer);
1778 break;
1779 }
1780 case SPIRV::OpExtInst: {
1781 if (MI.getOperand(2).getImm() ==
1782 static_cast<int64_t>(
1783 SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100)) {
1784 Reqs.addExtension(SPIRV::Extension::SPV_KHR_non_semantic_info);
1785 break;
1786 }
1787 if (MI.getOperand(3).getImm() ==
1788 static_cast<int64_t>(SPIRV::OpenCLExtInst::printf)) {
1789 addPrintfRequirements(MI, Reqs, ST);
1790 break;
1791 }
1792 if (MI.getOperand(2).getImm() ==
1793 static_cast<int64_t>(SPIRV::InstructionSet::OpenCL_std)) {
1794 const MachineFunction *MF = MI.getMF();
1795 const MachineRegisterInfo &MRI = MF->getRegInfo();
1796 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
1797
1798 auto IsBFloat16 = [&](SPIRVTypeInst TypeDef) {
1799 if (TypeDef && TypeDef->getOpcode() == SPIRV::OpTypeVector)
1800 TypeDef = MRI.getVRegDef(TypeDef->getOperand(1).getReg());
1801 return isBFloat16Type(TypeDef);
1802 };
1803
1804 // Result type is operand 1; arguments start at operand 4.
1805 bool UsesBFloat16 = IsBFloat16(MRI.getVRegDef(MI.getOperand(1).getReg()));
1806 for (unsigned I = 4, E = MI.getNumOperands(); I < E && !UsesBFloat16;
1807 ++I) {
1808 const MachineOperand &MO = MI.getOperand(I);
1809 if (MO.isReg())
1810 UsesBFloat16 = IsBFloat16(GR->getResultType(
1811 MO.getReg(), const_cast<MachineFunction *>(MF)));
1812 }
1813
1814 if (UsesBFloat16) {
1815 if (!ST.canUseExtension(
1816 SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic)) {
1818 MI, "OpenCL Extended instructions with bfloat16 require the "
1819 "following SPIR-V extension: SPV_INTEL_bfloat16_arithmetic");
1820 break;
1821 }
1822 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic);
1823 Reqs.addCapability(SPIRV::Capability::BFloat16ArithmeticINTEL);
1824 }
1825 }
1826 break;
1827 }
1828 case SPIRV::OpAliasDomainDeclINTEL:
1829 case SPIRV::OpAliasScopeDeclINTEL:
1830 case SPIRV::OpAliasScopeListDeclINTEL: {
1831 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing);
1832 Reqs.addCapability(SPIRV::Capability::MemoryAccessAliasingINTEL);
1833 break;
1834 }
1835 case SPIRV::OpBitReverse:
1836 case SPIRV::OpBitFieldInsert:
1837 case SPIRV::OpBitFieldSExtract:
1838 case SPIRV::OpBitFieldUExtract:
1839 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions)) {
1840 Reqs.addCapability(SPIRV::Capability::Shader);
1841 break;
1842 }
1843 Reqs.addExtension(SPIRV::Extension::SPV_KHR_bit_instructions);
1844 Reqs.addCapability(SPIRV::Capability::BitInstructions);
1845 break;
1846 case SPIRV::OpTypeRuntimeArray:
1847 Reqs.addCapability(SPIRV::Capability::Shader);
1848 break;
1849 case SPIRV::OpTypeOpaque:
1850 case SPIRV::OpTypeEvent:
1851 Reqs.addCapability(SPIRV::Capability::Kernel);
1852 break;
1853 case SPIRV::OpTypePipe:
1854 case SPIRV::OpTypeReserveId:
1855 Reqs.addCapability(SPIRV::Capability::Pipes);
1856 break;
1857 case SPIRV::OpTypePipeStorage:
1858 Reqs.addCapability(SPIRV::Capability::PipeStorage);
1859 break;
1860 case SPIRV::OpTypeDeviceEvent:
1861 case SPIRV::OpTypeQueue:
1862 case SPIRV::OpBuildNDRange:
1863 case SPIRV::OpEnqueueKernel:
1864 case SPIRV::OpGetKernelNDrangeSubGroupCount:
1865 case SPIRV::OpGetKernelNDrangeMaxSubGroupSize:
1866 case SPIRV::OpGetKernelWorkGroupSize:
1867 case SPIRV::OpGetKernelPreferredWorkGroupSizeMultiple:
1868 Reqs.addCapability(SPIRV::Capability::DeviceEnqueue);
1869 break;
1870 case SPIRV::OpDecorate:
1871 case SPIRV::OpDecorateId:
1872 case SPIRV::OpDecorateString:
1873 addOpDecorateReqs(MI, 1, Reqs, ST);
1874 break;
1875 case SPIRV::OpMemberDecorate:
1876 case SPIRV::OpMemberDecorateString:
1877 addOpDecorateReqs(MI, 2, Reqs, ST);
1878 break;
1879 case SPIRV::OpInBoundsPtrAccessChain:
1880 Reqs.addCapability(SPIRV::Capability::Addresses);
1881 break;
1882 case SPIRV::OpConstantSampler:
1883 Reqs.addCapability(SPIRV::Capability::LiteralSampler);
1884 break;
1885 case SPIRV::OpInBoundsAccessChain:
1886 case SPIRV::OpAccessChain:
1887 addOpAccessChainReqs(MI, Reqs, ST);
1888 break;
1889 case SPIRV::OpTypeImage:
1890 addOpTypeImageReqs(MI, Reqs, ST);
1891 break;
1892 case SPIRV::OpTypeSampler:
1893 if (!ST.isShader()) {
1894 Reqs.addCapability(SPIRV::Capability::ImageBasic);
1895 }
1896 break;
1897 case SPIRV::OpTypeForwardPointer:
1898 // TODO: check if it's OpenCL's kernel.
1899 Reqs.addCapability(SPIRV::Capability::Addresses);
1900 break;
1901 case SPIRV::OpAtomicFlagTestAndSet:
1902 case SPIRV::OpAtomicLoad:
1903 case SPIRV::OpAtomicStore:
1904 case SPIRV::OpAtomicExchange:
1905 case SPIRV::OpAtomicCompareExchange:
1906 case SPIRV::OpAtomicCompareExchangeWeak:
1907 case SPIRV::OpAtomicIIncrement:
1908 case SPIRV::OpAtomicIDecrement:
1909 case SPIRV::OpAtomicIAdd:
1910 case SPIRV::OpAtomicISub:
1911 case SPIRV::OpAtomicUMin:
1912 case SPIRV::OpAtomicUMax:
1913 case SPIRV::OpAtomicSMin:
1914 case SPIRV::OpAtomicSMax:
1915 case SPIRV::OpAtomicAnd:
1916 case SPIRV::OpAtomicOr:
1917 case SPIRV::OpAtomicXor: {
1918 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1919 SPIRVTypeInst TypeDef;
1920 if (Op == SPIRV::OpAtomicStore) {
1921 assert(MI.getOperand(3).isReg());
1922 TypeDef = getRegType(MI.getOperand(3).getReg(), *MI.getMF(),
1923 ST.getSPIRVGlobalRegistry());
1924 assert(TypeDef && "Unexpected type instruction for OpAtomicStore");
1925 } else {
1926 assert(MI.getOperand(1).isReg() && "Unexpected operand in atomic");
1927 TypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
1928 }
1929
1930 if (TypeDef->getOpcode() == SPIRV::OpTypeInt) {
1931 unsigned BitWidth = TypeDef->getOperand(1).getImm();
1932 if (BitWidth == 64)
1933 Reqs.addCapability(SPIRV::Capability::Int64Atomics);
1934 else if (BitWidth == 16) {
1935 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics))
1937 "16-bit integer atomic operations require the following SPIR-V "
1938 "extension: SPV_INTEL_16bit_atomics",
1939 false);
1940 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics);
1941 switch (Op) {
1942 case SPIRV::OpAtomicLoad:
1943 case SPIRV::OpAtomicStore:
1944 case SPIRV::OpAtomicExchange:
1945 case SPIRV::OpAtomicCompareExchange:
1946 case SPIRV::OpAtomicCompareExchangeWeak:
1947 Reqs.addCapability(
1948 SPIRV::Capability::AtomicInt16CompareExchangeINTEL);
1949 break;
1950 default:
1951 Reqs.addCapability(SPIRV::Capability::Int16AtomicsINTEL);
1952 break;
1953 }
1954 }
1955 } else if (isBFloat16Type(TypeDef)) {
1956 if (is_contained({SPIRV::OpAtomicLoad, SPIRV::OpAtomicStore,
1957 SPIRV::OpAtomicExchange},
1958 Op)) {
1959 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics))
1961 "The atomic bfloat16 instruction requires the following SPIR-V "
1962 "extension: SPV_INTEL_16bit_atomics",
1963 false);
1964 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics);
1965 Reqs.addCapability(SPIRV::Capability::AtomicBFloat16LoadStoreINTEL);
1966 }
1967 }
1968 break;
1969 }
1970 case SPIRV::OpGroupNonUniformIAdd:
1971 case SPIRV::OpGroupNonUniformFAdd:
1972 case SPIRV::OpGroupNonUniformIMul:
1973 case SPIRV::OpGroupNonUniformFMul:
1974 case SPIRV::OpGroupNonUniformSMin:
1975 case SPIRV::OpGroupNonUniformUMin:
1976 case SPIRV::OpGroupNonUniformFMin:
1977 case SPIRV::OpGroupNonUniformSMax:
1978 case SPIRV::OpGroupNonUniformUMax:
1979 case SPIRV::OpGroupNonUniformFMax:
1980 case SPIRV::OpGroupNonUniformBitwiseAnd:
1981 case SPIRV::OpGroupNonUniformBitwiseOr:
1982 case SPIRV::OpGroupNonUniformBitwiseXor:
1983 case SPIRV::OpGroupNonUniformLogicalAnd:
1984 case SPIRV::OpGroupNonUniformLogicalOr:
1985 case SPIRV::OpGroupNonUniformLogicalXor: {
1986 assert(MI.getOperand(3).isImm());
1987 int64_t GroupOp = MI.getOperand(3).getImm();
1988 switch (GroupOp) {
1989 case SPIRV::GroupOperation::Reduce:
1990 case SPIRV::GroupOperation::InclusiveScan:
1991 case SPIRV::GroupOperation::ExclusiveScan:
1992 Reqs.addCapability(SPIRV::Capability::GroupNonUniformArithmetic);
1993 break;
1994 case SPIRV::GroupOperation::ClusteredReduce:
1995 Reqs.addCapability(SPIRV::Capability::GroupNonUniformClustered);
1996 break;
1997 case SPIRV::GroupOperation::PartitionedReduceNV:
1998 case SPIRV::GroupOperation::PartitionedInclusiveScanNV:
1999 case SPIRV::GroupOperation::PartitionedExclusiveScanNV:
2000 Reqs.addCapability(SPIRV::Capability::GroupNonUniformPartitionedNV);
2001 break;
2002 }
2003 break;
2004 }
2005 case SPIRV::OpGroupNonUniformQuadSwap:
2006 Reqs.addCapability(SPIRV::Capability::GroupNonUniformQuad);
2007 break;
2008 case SPIRV::OpImageQueryLod:
2009 Reqs.addCapability(SPIRV::Capability::ImageQuery);
2010 break;
2011 case SPIRV::OpImageQuerySize:
2012 case SPIRV::OpImageQuerySizeLod:
2013 case SPIRV::OpImageQueryLevels:
2014 case SPIRV::OpImageQuerySamples:
2015 if (ST.isShader())
2016 Reqs.addCapability(SPIRV::Capability::ImageQuery);
2017 break;
2018 case SPIRV::OpImageQueryFormat: {
2019 Register ResultReg = MI.getOperand(0).getReg();
2020 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
2021 static const unsigned CompareOps[] = {
2022 SPIRV::OpIEqual, SPIRV::OpINotEqual,
2023 SPIRV::OpUGreaterThan, SPIRV::OpUGreaterThanEqual,
2024 SPIRV::OpULessThan, SPIRV::OpULessThanEqual,
2025 SPIRV::OpSGreaterThan, SPIRV::OpSGreaterThanEqual,
2026 SPIRV::OpSLessThan, SPIRV::OpSLessThanEqual};
2027
2028 auto CheckAndAddExtension = [&](int64_t ImmVal) {
2029 if (ImmVal == 4323 || ImmVal == 4324) {
2030 if (ST.canUseExtension(SPIRV::Extension::SPV_EXT_image_raw10_raw12))
2031 Reqs.addExtension(SPIRV::Extension::SPV_EXT_image_raw10_raw12);
2032 else
2033 report_fatal_error("This requires the "
2034 "SPV_EXT_image_raw10_raw12 extension");
2035 }
2036 };
2037
2038 for (MachineInstr &UseInst : MRI.use_instructions(ResultReg)) {
2039 unsigned Opc = UseInst.getOpcode();
2040
2041 if (Opc == SPIRV::OpSwitch) {
2042 for (const MachineOperand &Op : UseInst.operands())
2043 if (Op.isImm())
2044 CheckAndAddExtension(Op.getImm());
2045 } else if (llvm::is_contained(CompareOps, Opc)) {
2046 for (unsigned i = 1; i < UseInst.getNumOperands(); ++i) {
2047 Register UseReg = UseInst.getOperand(i).getReg();
2048 MachineInstr *ConstInst = MRI.getVRegDef(UseReg);
2049 if (ConstInst && ConstInst->getOpcode() == SPIRV::OpConstantI) {
2050 int64_t ImmVal = ConstInst->getOperand(2).getImm();
2051 if (ImmVal)
2052 CheckAndAddExtension(ImmVal);
2053 }
2054 }
2055 }
2056 }
2057 break;
2058 }
2059
2060 case SPIRV::OpGroupNonUniformShuffle:
2061 case SPIRV::OpGroupNonUniformShuffleXor:
2062 Reqs.addCapability(SPIRV::Capability::GroupNonUniformShuffle);
2063 break;
2064 case SPIRV::OpGroupNonUniformShuffleUp:
2065 case SPIRV::OpGroupNonUniformShuffleDown:
2066 Reqs.addCapability(SPIRV::Capability::GroupNonUniformShuffleRelative);
2067 break;
2068 case SPIRV::OpGroupAll:
2069 case SPIRV::OpGroupAny:
2070 case SPIRV::OpGroupBroadcast:
2071 case SPIRV::OpGroupIAdd:
2072 case SPIRV::OpGroupFAdd:
2073 case SPIRV::OpGroupFMin:
2074 case SPIRV::OpGroupUMin:
2075 case SPIRV::OpGroupSMin:
2076 case SPIRV::OpGroupFMax:
2077 case SPIRV::OpGroupUMax:
2078 case SPIRV::OpGroupSMax:
2079 Reqs.addCapability(SPIRV::Capability::Groups);
2080 break;
2081 case SPIRV::OpGroupNonUniformElect:
2082 Reqs.addCapability(SPIRV::Capability::GroupNonUniform);
2083 break;
2084 case SPIRV::OpGroupNonUniformAll:
2085 case SPIRV::OpGroupNonUniformAny:
2086 case SPIRV::OpGroupNonUniformAllEqual:
2087 Reqs.addCapability(SPIRV::Capability::GroupNonUniformVote);
2088 break;
2089 case SPIRV::OpGroupNonUniformBroadcast:
2090 case SPIRV::OpGroupNonUniformBroadcastFirst:
2091 case SPIRV::OpGroupNonUniformBallot:
2092 case SPIRV::OpGroupNonUniformInverseBallot:
2093 case SPIRV::OpGroupNonUniformBallotBitExtract:
2094 case SPIRV::OpGroupNonUniformBallotBitCount:
2095 case SPIRV::OpGroupNonUniformBallotFindLSB:
2096 case SPIRV::OpGroupNonUniformBallotFindMSB:
2097 Reqs.addCapability(SPIRV::Capability::GroupNonUniformBallot);
2098 break;
2099 case SPIRV::OpSubgroupShuffleINTEL:
2100 case SPIRV::OpSubgroupShuffleDownINTEL:
2101 case SPIRV::OpSubgroupShuffleUpINTEL:
2102 case SPIRV::OpSubgroupShuffleXorINTEL:
2103 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
2104 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
2105 Reqs.addCapability(SPIRV::Capability::SubgroupShuffleINTEL);
2106 }
2107 break;
2108 case SPIRV::OpSubgroupBlockReadINTEL:
2109 case SPIRV::OpSubgroupBlockWriteINTEL:
2110 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
2111 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
2112 Reqs.addCapability(SPIRV::Capability::SubgroupBufferBlockIOINTEL);
2113 }
2114 break;
2115 case SPIRV::OpSubgroupImageBlockReadINTEL:
2116 case SPIRV::OpSubgroupImageBlockWriteINTEL:
2117 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
2118 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
2119 Reqs.addCapability(SPIRV::Capability::SubgroupImageBlockIOINTEL);
2120 }
2121 break;
2122 case SPIRV::OpSubgroupImageMediaBlockReadINTEL:
2123 case SPIRV::OpSubgroupImageMediaBlockWriteINTEL:
2124 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_media_block_io)) {
2125 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_media_block_io);
2126 Reqs.addCapability(SPIRV::Capability::SubgroupImageMediaBlockIOINTEL);
2127 }
2128 break;
2129 case SPIRV::OpAssumeTrueKHR:
2130 case SPIRV::OpExpectKHR:
2131 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) {
2132 Reqs.addExtension(SPIRV::Extension::SPV_KHR_expect_assume);
2133 Reqs.addCapability(SPIRV::Capability::ExpectAssumeKHR);
2134 }
2135 break;
2136 case SPIRV::OpFmaKHR:
2137 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_fma)) {
2138 Reqs.addExtension(SPIRV::Extension::SPV_KHR_fma);
2139 Reqs.addCapability(SPIRV::Capability::FmaKHR);
2140 }
2141 break;
2142 case SPIRV::OpPtrCastToCrossWorkgroupINTEL:
2143 case SPIRV::OpCrossWorkgroupCastToPtrINTEL:
2144 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes)) {
2145 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes);
2146 Reqs.addCapability(SPIRV::Capability::USMStorageClassesINTEL);
2147 }
2148 break;
2149 case SPIRV::OpConstantFunctionPointerINTEL:
2150 case SPIRV::OpFunctionPointerCallINTEL:
2151 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)) {
2152 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
2153 Reqs.addCapability(SPIRV::Capability::FunctionPointersINTEL);
2154 }
2155 break;
2156 case SPIRV::OpGroupNonUniformRotateKHR:
2157 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_subgroup_rotate))
2158 report_fatal_error("OpGroupNonUniformRotateKHR instruction requires the "
2159 "following SPIR-V extension: SPV_KHR_subgroup_rotate",
2160 false);
2161 Reqs.addExtension(SPIRV::Extension::SPV_KHR_subgroup_rotate);
2162 Reqs.addCapability(SPIRV::Capability::GroupNonUniformRotateKHR);
2163 Reqs.addCapability(SPIRV::Capability::GroupNonUniform);
2164 break;
2165 case SPIRV::OpFixedCosALTERA:
2166 case SPIRV::OpFixedSinALTERA:
2167 case SPIRV::OpFixedCosPiALTERA:
2168 case SPIRV::OpFixedSinPiALTERA:
2169 case SPIRV::OpFixedExpALTERA:
2170 case SPIRV::OpFixedLogALTERA:
2171 case SPIRV::OpFixedRecipALTERA:
2172 case SPIRV::OpFixedSqrtALTERA:
2173 case SPIRV::OpFixedSinCosALTERA:
2174 case SPIRV::OpFixedSinCosPiALTERA:
2175 case SPIRV::OpFixedRsqrtALTERA:
2176 if (!ST.canUseExtension(
2177 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_fixed_point))
2178 report_fatal_error("This instruction requires the "
2179 "following SPIR-V extension: "
2180 "SPV_ALTERA_arbitrary_precision_fixed_point",
2181 false);
2182 Reqs.addExtension(
2183 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_fixed_point);
2184 Reqs.addCapability(SPIRV::Capability::ArbitraryPrecisionFixedPointALTERA);
2185 break;
2186 case SPIRV::OpGroupIMulKHR:
2187 case SPIRV::OpGroupFMulKHR:
2188 case SPIRV::OpGroupBitwiseAndKHR:
2189 case SPIRV::OpGroupBitwiseOrKHR:
2190 case SPIRV::OpGroupBitwiseXorKHR:
2191 case SPIRV::OpGroupLogicalAndKHR:
2192 case SPIRV::OpGroupLogicalOrKHR:
2193 case SPIRV::OpGroupLogicalXorKHR:
2194 if (ST.canUseExtension(
2195 SPIRV::Extension::SPV_KHR_uniform_group_instructions)) {
2196 Reqs.addExtension(SPIRV::Extension::SPV_KHR_uniform_group_instructions);
2197 Reqs.addCapability(SPIRV::Capability::GroupUniformArithmeticKHR);
2198 }
2199 break;
2200 case SPIRV::OpReadClockKHR:
2201 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_shader_clock))
2202 report_fatal_error("OpReadClockKHR instruction requires the "
2203 "following SPIR-V extension: SPV_KHR_shader_clock",
2204 false);
2205 Reqs.addExtension(SPIRV::Extension::SPV_KHR_shader_clock);
2206 Reqs.addCapability(SPIRV::Capability::ShaderClockKHR);
2207 break;
2208 case SPIRV::OpAbortKHR:
2209 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort))
2210 report_fatal_error("OpAbortKHR instruction requires the "
2211 "following SPIR-V extension: SPV_KHR_abort",
2212 false);
2213 Reqs.addExtension(SPIRV::Extension::SPV_KHR_abort);
2214 Reqs.addCapability(SPIRV::Capability::AbortKHR);
2215 break;
2216 case SPIRV::OpPoisonKHR:
2217 case SPIRV::OpFreezeKHR:
2218 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_poison_freeze))
2219 report_fatal_error("OpPoisonKHR/OpFreezeKHR instruction requires the "
2220 "following SPIR-V extension: SPV_KHR_poison_freeze",
2221 false);
2222 Reqs.addExtension(SPIRV::Extension::SPV_KHR_poison_freeze);
2223 Reqs.addCapability(SPIRV::Capability::PoisonFreezeKHR);
2224 break;
2225 case SPIRV::OpAtomicFAddEXT:
2226 case SPIRV::OpAtomicFMinEXT:
2227 case SPIRV::OpAtomicFMaxEXT:
2228 AddAtomicFloatRequirements(MI, Reqs, ST);
2229 break;
2230 case SPIRV::OpConvertBF16ToFINTEL:
2231 case SPIRV::OpConvertFToBF16INTEL:
2232 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bfloat16_conversion)) {
2233 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_conversion);
2234 Reqs.addCapability(SPIRV::Capability::BFloat16ConversionINTEL);
2235 }
2236 break;
2237 case SPIRV::OpRoundFToTF32INTEL:
2238 if (ST.canUseExtension(
2239 SPIRV::Extension::SPV_INTEL_tensor_float32_conversion)) {
2240 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_tensor_float32_conversion);
2241 Reqs.addCapability(SPIRV::Capability::TensorFloat32RoundingINTEL);
2242 }
2243 break;
2244 case SPIRV::OpVariableLengthArrayINTEL:
2245 case SPIRV::OpSaveMemoryINTEL:
2246 case SPIRV::OpRestoreMemoryINTEL:
2247 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array)) {
2248 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_variable_length_array);
2249 Reqs.addCapability(SPIRV::Capability::VariableLengthArrayINTEL);
2250 }
2251 break;
2252 case SPIRV::OpUntypedVariableLengthArrayINTEL:
2253 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array)) {
2254 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_variable_length_array);
2255 Reqs.addCapability(SPIRV::Capability::UntypedVariableLengthArrayINTEL);
2256 }
2257 break;
2258 case SPIRV::OpAsmTargetINTEL:
2259 case SPIRV::OpAsmINTEL:
2260 case SPIRV::OpAsmCallINTEL:
2261 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_inline_assembly)) {
2262 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_inline_assembly);
2263 Reqs.addCapability(SPIRV::Capability::AsmINTEL);
2264 }
2265 break;
2266 case SPIRV::OpTypeCooperativeMatrixKHR: {
2267 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix))
2269 "OpTypeCooperativeMatrixKHR type requires the "
2270 "following SPIR-V extension: SPV_KHR_cooperative_matrix",
2271 false);
2272 Reqs.addExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix);
2273 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixKHR);
2274 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
2275 SPIRVTypeInst TypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
2276 if (isBFloat16Type(TypeDef))
2277 Reqs.addCapability(SPIRV::Capability::BFloat16CooperativeMatrixKHR);
2278 break;
2279 }
2280 case SPIRV::OpArithmeticFenceEXT:
2281 if (!ST.canUseExtension(SPIRV::Extension::SPV_EXT_arithmetic_fence))
2282 report_fatal_error("OpArithmeticFenceEXT requires the "
2283 "following SPIR-V extension: SPV_EXT_arithmetic_fence",
2284 false);
2285 Reqs.addExtension(SPIRV::Extension::SPV_EXT_arithmetic_fence);
2286 Reqs.addCapability(SPIRV::Capability::ArithmeticFenceEXT);
2287 break;
2288 case SPIRV::OpControlBarrierArriveINTEL:
2289 case SPIRV::OpControlBarrierWaitINTEL:
2290 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_split_barrier)) {
2291 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_split_barrier);
2292 Reqs.addCapability(SPIRV::Capability::SplitBarrierINTEL);
2293 }
2294 break;
2295 case SPIRV::OpCooperativeMatrixMulAddKHR: {
2296 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix))
2297 report_fatal_error("Cooperative matrix instructions require the "
2298 "following SPIR-V extension: "
2299 "SPV_KHR_cooperative_matrix",
2300 false);
2301 Reqs.addExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix);
2302 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixKHR);
2303 constexpr unsigned MulAddMaxSize = 6;
2304 if (MI.getNumOperands() != MulAddMaxSize)
2305 break;
2306 const int64_t CoopOperands = MI.getOperand(MulAddMaxSize - 1).getImm();
2307 if (CoopOperands &
2308 SPIRV::CooperativeMatrixOperands::MatrixAAndBTF32ComponentsINTEL) {
2309 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2310 report_fatal_error("MatrixAAndBTF32ComponentsINTEL type interpretation "
2311 "require the following SPIR-V extension: "
2312 "SPV_INTEL_joint_matrix",
2313 false);
2314 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2315 Reqs.addCapability(
2316 SPIRV::Capability::CooperativeMatrixTF32ComponentTypeINTEL);
2317 }
2318 if (CoopOperands & SPIRV::CooperativeMatrixOperands::
2319 MatrixAAndBBFloat16ComponentsINTEL ||
2320 CoopOperands &
2321 SPIRV::CooperativeMatrixOperands::MatrixCBFloat16ComponentsINTEL ||
2322 CoopOperands & SPIRV::CooperativeMatrixOperands::
2323 MatrixResultBFloat16ComponentsINTEL) {
2324 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2325 report_fatal_error("***BF16ComponentsINTEL type interpretations "
2326 "require the following SPIR-V extension: "
2327 "SPV_INTEL_joint_matrix",
2328 false);
2329 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2330 Reqs.addCapability(
2331 SPIRV::Capability::CooperativeMatrixBFloat16ComponentTypeINTEL);
2332 }
2333 break;
2334 }
2335 case SPIRV::OpCooperativeMatrixLoadKHR:
2336 case SPIRV::OpCooperativeMatrixStoreKHR:
2337 case SPIRV::OpCooperativeMatrixLoadCheckedINTEL:
2338 case SPIRV::OpCooperativeMatrixStoreCheckedINTEL:
2339 case SPIRV::OpCooperativeMatrixPrefetchINTEL: {
2340 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix))
2341 report_fatal_error("Cooperative matrix instructions require the "
2342 "following SPIR-V extension: "
2343 "SPV_KHR_cooperative_matrix",
2344 false);
2345 Reqs.addExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix);
2346 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixKHR);
2347
2348 // Check Layout operand in case if it's not a standard one and add the
2349 // appropriate capability.
2350 unsigned LayoutNum;
2351 switch (Op) {
2352 case SPIRV::OpCooperativeMatrixLoadKHR:
2353 LayoutNum = 3;
2354 break;
2355 case SPIRV::OpCooperativeMatrixStoreKHR:
2356 LayoutNum = 2;
2357 break;
2358 case SPIRV::OpCooperativeMatrixLoadCheckedINTEL:
2359 LayoutNum = 5;
2360 break;
2361 case SPIRV::OpCooperativeMatrixStoreCheckedINTEL:
2362 case SPIRV::OpCooperativeMatrixPrefetchINTEL:
2363 LayoutNum = 4;
2364 break;
2365 default:
2366 llvm_unreachable("unexpected cooperative matrix opcode");
2367 }
2368 Register RegLayout = MI.getOperand(LayoutNum).getReg();
2369 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
2370 MachineInstr *MILayout = MRI.getUniqueVRegDef(RegLayout);
2371 if (MILayout->getOpcode() == SPIRV::OpConstantI) {
2372 const unsigned LayoutVal = MILayout->getOperand(2).getImm();
2373 if (LayoutVal ==
2374 static_cast<unsigned>(SPIRV::CooperativeMatrixLayout::PackedINTEL)) {
2375 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2376 report_fatal_error("PackedINTEL layout require the following SPIR-V "
2377 "extension: SPV_INTEL_joint_matrix",
2378 false);
2379 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2380 Reqs.addCapability(SPIRV::Capability::PackedCooperativeMatrixINTEL);
2381 }
2382 }
2383
2384 // Nothing to do.
2385 if (Op == SPIRV::OpCooperativeMatrixLoadKHR ||
2386 Op == SPIRV::OpCooperativeMatrixStoreKHR)
2387 break;
2388
2389 std::string InstName;
2390 switch (Op) {
2391 case SPIRV::OpCooperativeMatrixPrefetchINTEL:
2392 InstName = "OpCooperativeMatrixPrefetchINTEL";
2393 break;
2394 case SPIRV::OpCooperativeMatrixLoadCheckedINTEL:
2395 InstName = "OpCooperativeMatrixLoadCheckedINTEL";
2396 break;
2397 case SPIRV::OpCooperativeMatrixStoreCheckedINTEL:
2398 InstName = "OpCooperativeMatrixStoreCheckedINTEL";
2399 break;
2400 }
2401
2402 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix)) {
2403 const std::string ErrorMsg =
2404 InstName + " instruction requires the "
2405 "following SPIR-V extension: SPV_INTEL_joint_matrix";
2406 report_fatal_error(ErrorMsg.c_str(), false);
2407 }
2408 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2409 if (Op == SPIRV::OpCooperativeMatrixPrefetchINTEL) {
2410 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixPrefetchINTEL);
2411 break;
2412 }
2413 Reqs.addCapability(
2414 SPIRV::Capability::CooperativeMatrixCheckedInstructionsINTEL);
2415 break;
2416 }
2417 case SPIRV::OpCooperativeMatrixConstructCheckedINTEL:
2418 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2419 report_fatal_error("OpCooperativeMatrixConstructCheckedINTEL "
2420 "instructions require the following SPIR-V extension: "
2421 "SPV_INTEL_joint_matrix",
2422 false);
2423 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2424 Reqs.addCapability(
2425 SPIRV::Capability::CooperativeMatrixCheckedInstructionsINTEL);
2426 break;
2427 case SPIRV::OpReadPipeBlockingALTERA:
2428 case SPIRV::OpWritePipeBlockingALTERA:
2429 if (ST.canUseExtension(SPIRV::Extension::SPV_ALTERA_blocking_pipes)) {
2430 Reqs.addExtension(SPIRV::Extension::SPV_ALTERA_blocking_pipes);
2431 Reqs.addCapability(SPIRV::Capability::BlockingPipesALTERA);
2432 }
2433 break;
2434 case SPIRV::OpCooperativeMatrixGetElementCoordINTEL:
2435 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2436 report_fatal_error("OpCooperativeMatrixGetElementCoordINTEL requires the "
2437 "following SPIR-V extension: SPV_INTEL_joint_matrix",
2438 false);
2439 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2440 Reqs.addCapability(
2441 SPIRV::Capability::CooperativeMatrixInvocationInstructionsINTEL);
2442 break;
2443 case SPIRV::OpConvertHandleToImageINTEL:
2444 case SPIRV::OpConvertHandleToSamplerINTEL:
2445 case SPIRV::OpConvertHandleToSampledImageINTEL: {
2446 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bindless_images))
2447 report_fatal_error("OpConvertHandleTo[Image/Sampler/SampledImage]INTEL "
2448 "instructions require the following SPIR-V extension: "
2449 "SPV_INTEL_bindless_images",
2450 false);
2451 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
2452 SPIRV::AddressingModel::AddressingModel AddrModel = MAI.Addr;
2453 SPIRVTypeInst TyDef = GR->getSPIRVTypeForVReg(MI.getOperand(1).getReg());
2454 if (Op == SPIRV::OpConvertHandleToImageINTEL &&
2455 TyDef->getOpcode() != SPIRV::OpTypeImage) {
2456 report_fatal_error("Incorrect return type for the instruction "
2457 "OpConvertHandleToImageINTEL",
2458 false);
2459 } else if (Op == SPIRV::OpConvertHandleToSamplerINTEL &&
2460 TyDef->getOpcode() != SPIRV::OpTypeSampler) {
2461 report_fatal_error("Incorrect return type for the instruction "
2462 "OpConvertHandleToSamplerINTEL",
2463 false);
2464 } else if (Op == SPIRV::OpConvertHandleToSampledImageINTEL &&
2465 TyDef->getOpcode() != SPIRV::OpTypeSampledImage) {
2466 report_fatal_error("Incorrect return type for the instruction "
2467 "OpConvertHandleToSampledImageINTEL",
2468 false);
2469 }
2470 SPIRVTypeInst SpvTy =
2471 getRegType(MI.getOperand(2).getReg(), *MI.getMF(), GR);
2472 unsigned Bitwidth = GR->getScalarOrVectorBitWidth(SpvTy);
2473 if (!(Bitwidth == 32 && AddrModel == SPIRV::AddressingModel::Physical32) &&
2474 !(Bitwidth == 64 && AddrModel == SPIRV::AddressingModel::Physical64)) {
2476 "Parameter value must be a 32-bit scalar in case of "
2477 "Physical32 addressing model or a 64-bit scalar in case of "
2478 "Physical64 addressing model",
2479 false);
2480 }
2481 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bindless_images);
2482 Reqs.addCapability(SPIRV::Capability::BindlessImagesINTEL);
2483 break;
2484 }
2485 case SPIRV::OpSubgroup2DBlockLoadINTEL:
2486 case SPIRV::OpSubgroup2DBlockLoadTransposeINTEL:
2487 case SPIRV::OpSubgroup2DBlockLoadTransformINTEL:
2488 case SPIRV::OpSubgroup2DBlockPrefetchINTEL:
2489 case SPIRV::OpSubgroup2DBlockStoreINTEL: {
2490 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_2d_block_io))
2491 report_fatal_error("OpSubgroup2DBlock[Load/LoadTranspose/LoadTransform/"
2492 "Prefetch/Store]INTEL instructions require the "
2493 "following SPIR-V extension: SPV_INTEL_2d_block_io",
2494 false);
2495 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_2d_block_io);
2496 Reqs.addCapability(SPIRV::Capability::Subgroup2DBlockIOINTEL);
2497
2498 if (Op == SPIRV::OpSubgroup2DBlockLoadTransposeINTEL) {
2499 Reqs.addCapability(SPIRV::Capability::Subgroup2DBlockTransposeINTEL);
2500 break;
2501 }
2502 if (Op == SPIRV::OpSubgroup2DBlockLoadTransformINTEL) {
2503 Reqs.addCapability(SPIRV::Capability::Subgroup2DBlockTransformINTEL);
2504 break;
2505 }
2506 break;
2507 }
2508 case SPIRV::OpKill: {
2509 Reqs.addCapability(SPIRV::Capability::Shader);
2510 } break;
2511 case SPIRV::OpDemoteToHelperInvocation:
2512 Reqs.addCapability(SPIRV::Capability::DemoteToHelperInvocation);
2513
2514 if (ST.canUseExtension(
2515 SPIRV::Extension::SPV_EXT_demote_to_helper_invocation)) {
2516 if (!ST.isAtLeastSPIRVVer(llvm::VersionTuple(1, 6)))
2517 Reqs.addExtension(
2518 SPIRV::Extension::SPV_EXT_demote_to_helper_invocation);
2519 }
2520 break;
2521 case SPIRV::OpSDot:
2522 case SPIRV::OpUDot:
2523 case SPIRV::OpSUDot:
2524 case SPIRV::OpSDotAccSat:
2525 case SPIRV::OpUDotAccSat:
2526 case SPIRV::OpSUDotAccSat:
2527 AddDotProductRequirements(MI, Reqs, ST);
2528 break;
2529 case SPIRV::OpImageSampleImplicitLod:
2530 case SPIRV::OpImageFetch:
2531 Reqs.addCapability(SPIRV::Capability::Shader);
2532 addImageOperandReqs(MI, Reqs, ST, 4);
2533 break;
2534 case SPIRV::OpImageSampleExplicitLod:
2535 addImageOperandReqs(MI, Reqs, ST, 4);
2536 break;
2537 case SPIRV::OpImageSampleDrefImplicitLod:
2538 case SPIRV::OpImageSampleDrefExplicitLod:
2539 case SPIRV::OpImageDrefGather:
2540 case SPIRV::OpImageGather:
2541 Reqs.addCapability(SPIRV::Capability::Shader);
2542 addImageOperandReqs(MI, Reqs, ST, 5);
2543 break;
2544 case SPIRV::OpImageRead: {
2545 Register ImageReg = MI.getOperand(2).getReg();
2546 SPIRVTypeInst TypeDef = ST.getSPIRVGlobalRegistry()->getResultType(
2547 ImageReg, const_cast<MachineFunction *>(MI.getMF()));
2548 // OpImageRead and OpImageWrite can use Unknown Image Formats
2549 // when the Kernel capability is declared. In the OpenCL environment we are
2550 // not allowed to produce
2551 // StorageImageReadWithoutFormat/StorageImageWriteWithoutFormat, see
2552 // https://github.com/KhronosGroup/SPIRV-Headers/issues/487
2553
2554 if (isImageTypeWithUnknownFormat(TypeDef) && ST.isShader())
2555 Reqs.addCapability(SPIRV::Capability::StorageImageReadWithoutFormat);
2556 break;
2557 }
2558 case SPIRV::OpImageWrite: {
2559 Register ImageReg = MI.getOperand(0).getReg();
2560 SPIRVTypeInst TypeDef = ST.getSPIRVGlobalRegistry()->getResultType(
2561 ImageReg, const_cast<MachineFunction *>(MI.getMF()));
2562 // OpImageRead and OpImageWrite can use Unknown Image Formats
2563 // when the Kernel capability is declared. In the OpenCL environment we are
2564 // not allowed to produce
2565 // StorageImageReadWithoutFormat/StorageImageWriteWithoutFormat, see
2566 // https://github.com/KhronosGroup/SPIRV-Headers/issues/487
2567
2568 if (isImageTypeWithUnknownFormat(TypeDef) && ST.isShader())
2569 Reqs.addCapability(SPIRV::Capability::StorageImageWriteWithoutFormat);
2570 break;
2571 }
2572 case SPIRV::OpTypeStructContinuedINTEL:
2573 case SPIRV::OpConstantCompositeContinuedINTEL:
2574 case SPIRV::OpSpecConstantCompositeContinuedINTEL:
2575 case SPIRV::OpCompositeConstructContinuedINTEL: {
2576 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_long_composites))
2578 "Continued instructions require the "
2579 "following SPIR-V extension: SPV_INTEL_long_composites",
2580 false);
2581 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_long_composites);
2582 Reqs.addCapability(SPIRV::Capability::LongCompositesINTEL);
2583 break;
2584 }
2585 case SPIRV::OpArbitraryFloatEQALTERA:
2586 case SPIRV::OpArbitraryFloatGEALTERA:
2587 case SPIRV::OpArbitraryFloatGTALTERA:
2588 case SPIRV::OpArbitraryFloatLEALTERA:
2589 case SPIRV::OpArbitraryFloatLTALTERA:
2590 case SPIRV::OpArbitraryFloatCbrtALTERA:
2591 case SPIRV::OpArbitraryFloatCosALTERA:
2592 case SPIRV::OpArbitraryFloatCosPiALTERA:
2593 case SPIRV::OpArbitraryFloatExp10ALTERA:
2594 case SPIRV::OpArbitraryFloatExp2ALTERA:
2595 case SPIRV::OpArbitraryFloatExpALTERA:
2596 case SPIRV::OpArbitraryFloatExpm1ALTERA:
2597 case SPIRV::OpArbitraryFloatHypotALTERA:
2598 case SPIRV::OpArbitraryFloatLog10ALTERA:
2599 case SPIRV::OpArbitraryFloatLog1pALTERA:
2600 case SPIRV::OpArbitraryFloatLog2ALTERA:
2601 case SPIRV::OpArbitraryFloatLogALTERA:
2602 case SPIRV::OpArbitraryFloatRecipALTERA:
2603 case SPIRV::OpArbitraryFloatSinCosALTERA:
2604 case SPIRV::OpArbitraryFloatSinCosPiALTERA:
2605 case SPIRV::OpArbitraryFloatSinALTERA:
2606 case SPIRV::OpArbitraryFloatSinPiALTERA:
2607 case SPIRV::OpArbitraryFloatSqrtALTERA:
2608 case SPIRV::OpArbitraryFloatACosALTERA:
2609 case SPIRV::OpArbitraryFloatACosPiALTERA:
2610 case SPIRV::OpArbitraryFloatAddALTERA:
2611 case SPIRV::OpArbitraryFloatASinALTERA:
2612 case SPIRV::OpArbitraryFloatASinPiALTERA:
2613 case SPIRV::OpArbitraryFloatATan2ALTERA:
2614 case SPIRV::OpArbitraryFloatATanALTERA:
2615 case SPIRV::OpArbitraryFloatATanPiALTERA:
2616 case SPIRV::OpArbitraryFloatCastFromIntALTERA:
2617 case SPIRV::OpArbitraryFloatCastALTERA:
2618 case SPIRV::OpArbitraryFloatCastToIntALTERA:
2619 case SPIRV::OpArbitraryFloatDivALTERA:
2620 case SPIRV::OpArbitraryFloatMulALTERA:
2621 case SPIRV::OpArbitraryFloatPowALTERA:
2622 case SPIRV::OpArbitraryFloatPowNALTERA:
2623 case SPIRV::OpArbitraryFloatPowRALTERA:
2624 case SPIRV::OpArbitraryFloatRSqrtALTERA:
2625 case SPIRV::OpArbitraryFloatSubALTERA: {
2626 if (!ST.canUseExtension(
2627 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_floating_point))
2629 "Floating point instructions can't be translated correctly without "
2630 "enabled SPV_ALTERA_arbitrary_precision_floating_point extension!",
2631 false);
2632 Reqs.addExtension(
2633 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_floating_point);
2634 Reqs.addCapability(
2635 SPIRV::Capability::ArbitraryPrecisionFloatingPointALTERA);
2636 break;
2637 }
2638 case SPIRV::OpSubgroupMatrixMultiplyAccumulateINTEL: {
2639 if (!ST.canUseExtension(
2640 SPIRV::Extension::SPV_INTEL_subgroup_matrix_multiply_accumulate))
2642 "OpSubgroupMatrixMultiplyAccumulateINTEL instruction requires the "
2643 "following SPIR-V "
2644 "extension: SPV_INTEL_subgroup_matrix_multiply_accumulate",
2645 false);
2646 Reqs.addExtension(
2647 SPIRV::Extension::SPV_INTEL_subgroup_matrix_multiply_accumulate);
2648 Reqs.addCapability(
2649 SPIRV::Capability::SubgroupMatrixMultiplyAccumulateINTEL);
2650 break;
2651 }
2652 case SPIRV::OpBitwiseFunctionINTEL: {
2653 if (!ST.canUseExtension(
2654 SPIRV::Extension::SPV_INTEL_ternary_bitwise_function))
2656 "OpBitwiseFunctionINTEL instruction requires the following SPIR-V "
2657 "extension: SPV_INTEL_ternary_bitwise_function",
2658 false);
2659 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_ternary_bitwise_function);
2660 Reqs.addCapability(SPIRV::Capability::TernaryBitwiseFunctionINTEL);
2661 break;
2662 }
2663 case SPIRV::OpCopyMemorySized: {
2664 Reqs.addCapability(SPIRV::Capability::Addresses);
2665 // TODO: Add UntypedPointersKHR when implemented.
2666 break;
2667 }
2668 case SPIRV::OpTypeUntypedPointerKHR:
2669 Reqs.getAndAddRequirements(SPIRV::OperandCategory::StorageClassOperand,
2670 MI.getOperand(1).getImm(), ST);
2671 [[fallthrough]];
2672 case SPIRV::OpUntypedVariableKHR:
2673 case SPIRV::OpUntypedAccessChainKHR:
2674 case SPIRV::OpUntypedInBoundsAccessChainKHR:
2675 case SPIRV::OpUntypedPtrAccessChainKHR:
2676 case SPIRV::OpUntypedInBoundsPtrAccessChainKHR:
2677 case SPIRV::OpUntypedPrefetchKHR:
2678 case SPIRV::OpUntypedGroupAsyncCopyKHR: {
2679 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_untyped_pointers))
2680 report_fatal_error("Untyped pointer instructions require the following "
2681 "SPIR-V extension: SPV_KHR_untyped_pointers",
2682 false);
2683 Reqs.addExtension(SPIRV::Extension::SPV_KHR_untyped_pointers);
2684 Reqs.addCapability(SPIRV::Capability::UntypedPointersKHR);
2685 break;
2686 }
2687 case SPIRV::OpPredicatedLoadINTEL:
2688 case SPIRV::OpPredicatedStoreINTEL: {
2689 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_predicated_io))
2691 "OpPredicated[Load/Store]INTEL instructions require "
2692 "the following SPIR-V extension: SPV_INTEL_predicated_io",
2693 false);
2694 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_predicated_io);
2695 Reqs.addCapability(SPIRV::Capability::PredicatedIOINTEL);
2696 break;
2697 }
2698 case SPIRV::OpFAddS:
2699 case SPIRV::OpFSubS:
2700 case SPIRV::OpFMulS:
2701 case SPIRV::OpFDivS:
2702 case SPIRV::OpFRemS:
2703 case SPIRV::OpFMod:
2704 case SPIRV::OpFNegate:
2705 case SPIRV::OpFAddV:
2706 case SPIRV::OpFSubV:
2707 case SPIRV::OpFMulV:
2708 case SPIRV::OpFDivV:
2709 case SPIRV::OpFRemV:
2710 case SPIRV::OpFNegateV: {
2711 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
2712 SPIRVTypeInst TypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
2713 if (isVectorType(TypeDef))
2714 TypeDef = MRI.getVRegDef(TypeDef->getOperand(1).getReg());
2715 if (isBFloat16Type(TypeDef)) {
2716 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic))
2718 "Arithmetic instructions with bfloat16 arguments require the "
2719 "following SPIR-V extension: SPV_INTEL_bfloat16_arithmetic",
2720 false);
2721 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic);
2722 Reqs.addCapability(SPIRV::Capability::BFloat16ArithmeticINTEL);
2723 }
2724 break;
2725 }
2726 case SPIRV::OpOrdered:
2727 case SPIRV::OpUnordered:
2728 case SPIRV::OpFOrdEqual:
2729 case SPIRV::OpFOrdNotEqual:
2730 case SPIRV::OpFOrdLessThan:
2731 case SPIRV::OpFOrdLessThanEqual:
2732 case SPIRV::OpFOrdGreaterThan:
2733 case SPIRV::OpFOrdGreaterThanEqual:
2734 case SPIRV::OpFUnordEqual:
2735 case SPIRV::OpFUnordNotEqual:
2736 case SPIRV::OpFUnordLessThan:
2737 case SPIRV::OpFUnordLessThanEqual:
2738 case SPIRV::OpFUnordGreaterThan:
2739 case SPIRV::OpFUnordGreaterThanEqual: {
2740 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
2741 SPIRVTypeInst TypeDef = getRegType(MI.getOperand(2).getReg(), *MI.getMF(),
2742 ST.getSPIRVGlobalRegistry());
2743 assert(TypeDef && "Unexpected type instruction for comparison operand");
2744 if (isVectorType(TypeDef))
2745 TypeDef = MRI.getVRegDef(TypeDef->getOperand(1).getReg());
2746 if (isBFloat16Type(TypeDef)) {
2747 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic))
2749 "Relational instructions with bfloat16 arguments require the "
2750 "following SPIR-V extension: SPV_INTEL_bfloat16_arithmetic",
2751 false);
2752 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic);
2753 Reqs.addCapability(SPIRV::Capability::BFloat16ArithmeticINTEL);
2754 }
2755 break;
2756 }
2757 case SPIRV::OpDPdxCoarse:
2758 case SPIRV::OpDPdyCoarse:
2759 case SPIRV::OpDPdxFine:
2760 case SPIRV::OpDPdyFine: {
2761 Reqs.addCapability(SPIRV::Capability::DerivativeControl);
2762 break;
2763 }
2764 case SPIRV::OpLoopControlINTEL: {
2765 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_unstructured_loop_controls);
2766 Reqs.addCapability(SPIRV::Capability::UnstructuredLoopControlsINTEL);
2767 break;
2768 }
2769
2770 default:
2771 break;
2772 }
2773
2774 // If we require capability Shader, then we can remove the requirement for
2775 // the BitInstructions capability, since Shader is a superset capability
2776 // of BitInstructions.
2777 Reqs.removeCapabilityIf(SPIRV::Capability::BitInstructions,
2778 SPIRV::Capability::Shader);
2779}
2780
2782 MachineFunctionGetter GetMF, const SPIRVSubtarget &ST) {
2783 // Collect requirements for existing instructions.
2784 for (const Function &F : M) {
2785 MachineFunction *MF = GetMF(F);
2786 if (!MF)
2787 continue;
2788 for (const MachineBasicBlock &MBB : *MF)
2789 for (const MachineInstr &MI : MBB)
2790 addInstrRequirements(MI, MAI, ST);
2791 }
2792 // Collect requirements for OpExecutionMode instructions.
2793 auto Node = M.getNamedMetadata("spirv.ExecutionMode");
2794 if (Node) {
2795 bool RequireFloatControls = false, RequireIntelFloatControls2 = false,
2796 RequireKHRFloatControls2 = false,
2797 VerLower14 = !ST.isAtLeastSPIRVVer(VersionTuple(1, 4));
2798 bool HasIntelFloatControls2 =
2799 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_float_controls2);
2800 bool HasKHRFloatControls2 =
2801 ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2);
2802 for (unsigned i = 0; i < Node->getNumOperands(); i++) {
2803 MDNode *MDN = cast<MDNode>(Node->getOperand(i));
2804 const MDOperand &MDOp = MDN->getOperand(1);
2805 if (auto *CMeta = dyn_cast<ConstantAsMetadata>(MDOp)) {
2806 Constant *C = CMeta->getValue();
2807 if (ConstantInt *Const = dyn_cast<ConstantInt>(C)) {
2808 auto EM = Const->getZExtValue();
2809 // SPV_KHR_float_controls is not available until v1.4:
2810 // add SPV_KHR_float_controls if the version is too low
2811 switch (EM) {
2812 case SPIRV::ExecutionMode::DenormPreserve:
2813 case SPIRV::ExecutionMode::DenormFlushToZero:
2814 case SPIRV::ExecutionMode::RoundingModeRTE:
2815 case SPIRV::ExecutionMode::RoundingModeRTZ:
2816 RequireFloatControls = VerLower14;
2818 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2819 break;
2820 case SPIRV::ExecutionMode::RoundingModeRTPINTEL:
2821 case SPIRV::ExecutionMode::RoundingModeRTNINTEL:
2822 case SPIRV::ExecutionMode::FloatingPointModeALTINTEL:
2823 case SPIRV::ExecutionMode::FloatingPointModeIEEEINTEL:
2824 if (HasIntelFloatControls2) {
2825 RequireIntelFloatControls2 = true;
2827 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2828 }
2829 break;
2830 case SPIRV::ExecutionMode::FPFastMathDefault: {
2831 if (HasKHRFloatControls2) {
2832 RequireKHRFloatControls2 = true;
2834 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2835 }
2836 break;
2837 }
2838 case SPIRV::ExecutionMode::ContractionOff:
2839 case SPIRV::ExecutionMode::SignedZeroInfNanPreserve:
2840 if (HasKHRFloatControls2) {
2841 RequireKHRFloatControls2 = true;
2843 SPIRV::OperandCategory::ExecutionModeOperand,
2844 SPIRV::ExecutionMode::FPFastMathDefault, ST);
2845 } else {
2847 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2848 }
2849 break;
2850 default:
2852 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2853 }
2854 }
2855 }
2856 }
2857 if (RequireFloatControls &&
2858 ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls))
2859 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls);
2860 if (RequireIntelFloatControls2)
2861 MAI.Reqs.addExtension(SPIRV::Extension::SPV_INTEL_float_controls2);
2862 if (RequireKHRFloatControls2)
2863 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls2);
2864 }
2865 for (const Function &F : M) {
2866 if (F.isDeclaration())
2867 continue;
2868 if (F.getMetadata("reqd_work_group_size"))
2870 SPIRV::OperandCategory::ExecutionModeOperand,
2871 SPIRV::ExecutionMode::LocalSize, ST);
2872 if (F.getFnAttribute("hlsl.numthreads").isValid()) {
2874 SPIRV::OperandCategory::ExecutionModeOperand,
2875 SPIRV::ExecutionMode::LocalSize, ST);
2876 }
2877 if (F.getFnAttribute("enable-maximal-reconvergence").getValueAsBool()) {
2878 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_maximal_reconvergence);
2879 }
2880 if (F.getMetadata("work_group_size_hint"))
2882 SPIRV::OperandCategory::ExecutionModeOperand,
2883 SPIRV::ExecutionMode::LocalSizeHint, ST);
2884 if (F.getMetadata("intel_reqd_sub_group_size") ||
2885 F.getMetadata("reqd_sub_group_size"))
2887 SPIRV::OperandCategory::ExecutionModeOperand,
2888 SPIRV::ExecutionMode::SubgroupSize, ST);
2889 if (F.getMetadata("max_work_group_size"))
2891 SPIRV::OperandCategory::ExecutionModeOperand,
2892 SPIRV::ExecutionMode::MaxWorkgroupSizeINTEL, ST);
2893 if (F.getMetadata("vec_type_hint"))
2895 SPIRV::OperandCategory::ExecutionModeOperand,
2896 SPIRV::ExecutionMode::VecTypeHint, ST);
2897
2898 if (F.hasOptNone()) {
2899 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_optnone)) {
2900 MAI.Reqs.addExtension(SPIRV::Extension::SPV_INTEL_optnone);
2901 MAI.Reqs.addCapability(SPIRV::Capability::OptNoneINTEL);
2902 } else if (ST.canUseExtension(SPIRV::Extension::SPV_EXT_optnone)) {
2903 MAI.Reqs.addExtension(SPIRV::Extension::SPV_EXT_optnone);
2904 MAI.Reqs.addCapability(SPIRV::Capability::OptNoneEXT);
2905 }
2906 }
2907 }
2908}
2909
2910static unsigned getFastMathFlags(const MachineInstr &I,
2911 const SPIRVSubtarget &ST) {
2912 unsigned Flags = SPIRV::FPFastMathMode::None;
2913 bool CanUseKHRFloatControls2 =
2914 ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2);
2915 if (I.getFlag(MachineInstr::MIFlag::FmNoNans))
2916 Flags |= SPIRV::FPFastMathMode::NotNaN;
2917 if (I.getFlag(MachineInstr::MIFlag::FmNoInfs))
2918 Flags |= SPIRV::FPFastMathMode::NotInf;
2919 if (I.getFlag(MachineInstr::MIFlag::FmNsz))
2920 Flags |= SPIRV::FPFastMathMode::NSZ;
2921 if (I.getFlag(MachineInstr::MIFlag::FmArcp))
2922 Flags |= SPIRV::FPFastMathMode::AllowRecip;
2923 if (I.getFlag(MachineInstr::MIFlag::FmContract) && CanUseKHRFloatControls2)
2924 Flags |= SPIRV::FPFastMathMode::AllowContract;
2925 if (I.getFlag(MachineInstr::MIFlag::FmReassoc)) {
2926 if (CanUseKHRFloatControls2)
2927 // LLVM reassoc maps to SPIRV transform, see
2928 // https://github.com/KhronosGroup/SPIRV-Registry/issues/326 for details.
2929 // Because we are enabling AllowTransform, we must enable AllowReassoc and
2930 // AllowContract too, as required by SPIRV spec. Also, we used to map
2931 // MIFlag::FmReassoc to FPFastMathMode::Fast, which now should instead by
2932 // replaced by turning all the other bits instead. Therefore, we're
2933 // enabling every bit here except None and Fast.
2934 Flags |= SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
2935 SPIRV::FPFastMathMode::NSZ | SPIRV::FPFastMathMode::AllowRecip |
2936 SPIRV::FPFastMathMode::AllowTransform |
2937 SPIRV::FPFastMathMode::AllowReassoc |
2938 SPIRV::FPFastMathMode::AllowContract;
2939 else
2940 Flags |= SPIRV::FPFastMathMode::Fast;
2941 }
2942
2943 if (CanUseKHRFloatControls2) {
2944 // Error out if SPIRV::FPFastMathMode::Fast is enabled.
2945 assert(!(Flags & SPIRV::FPFastMathMode::Fast) &&
2946 "SPIRV::FPFastMathMode::Fast is deprecated and should not be used "
2947 "anymore.");
2948
2949 // Error out if AllowTransform is enabled without AllowReassoc and
2950 // AllowContract.
2951 assert((!(Flags & SPIRV::FPFastMathMode::AllowTransform) ||
2952 ((Flags & SPIRV::FPFastMathMode::AllowReassoc &&
2953 Flags & SPIRV::FPFastMathMode::AllowContract))) &&
2954 "SPIRV::FPFastMathMode::AllowTransform requires AllowReassoc and "
2955 "AllowContract flags to be enabled as well.");
2956 }
2957
2958 return Flags;
2959}
2960
2962 if (ST.isKernel())
2963 return true;
2964 if (ST.getSPIRVVersion() < VersionTuple(1, 2))
2965 return false;
2966 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2);
2967}
2968
2970 MachineInstr &I, const SPIRVSubtarget &ST, const SPIRVInstrInfo &TII,
2972 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec) {
2973 bool Changed = false;
2974 // Insert after I so that the decorated register is defined before its use.
2975 MachineBasicBlock::iterator InsertPt = std::next(I.getIterator());
2976 auto Decorate = [&](SPIRV::Decoration::Decoration Dec,
2977 ArrayRef<uint32_t> DecArgs) {
2978 MachineIRBuilder MIRBuilder(*I.getParent(), InsertPt);
2979 MIRBuilder.setDebugLoc(I.getDebugLoc());
2980 buildOpDecorate(I.getOperand(0).getReg(), MIRBuilder, Dec, DecArgs);
2981 Changed = true;
2982 };
2983 if (TII.canUseIntegerWrapDecoration(I)) {
2984 if (I.getFlag(MachineInstr::MIFlag::NoSWrap) &&
2986 SPIRV::OperandCategory::DecorationOperand,
2987 SPIRV::Decoration::NoSignedWrap, ST, Reqs)
2988 .IsSatisfiable)
2989 Decorate(SPIRV::Decoration::NoSignedWrap, {});
2990 if (I.getFlag(MachineInstr::MIFlag::NoUWrap) &&
2992 SPIRV::OperandCategory::DecorationOperand,
2993 SPIRV::Decoration::NoUnsignedWrap, ST, Reqs)
2994 .IsSatisfiable)
2995 Decorate(SPIRV::Decoration::NoUnsignedWrap, {});
2996 }
2997 // In Kernel environments, FPFastMathMode on OpExtInst is valid per core
2998 // spec. For other instruction types, SPV_KHR_float_controls2 is required.
2999 bool CanUseFM =
3000 TII.canUseFastMathFlags(
3001 I, ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2)) ||
3002 (ST.isKernel() && I.getOpcode() == SPIRV::OpExtInst);
3003 if (!CanUseFM)
3004 return Changed;
3005
3006 unsigned FMFlags = getFastMathFlags(I, ST);
3007 if (FMFlags == SPIRV::FPFastMathMode::None) {
3008 // We also need to check if any FPFastMathDefault info was set for the
3009 // types used in this instruction.
3010 if (FPFastMathDefaultInfoVec.empty())
3011 return Changed;
3012
3013 // Use the first operand's FP type for arithmetic and comparisons,
3014 // and the result type for calls and extended instructions.
3015 SPIRVTypeInst FPType =
3016 I.getOpcode() == SPIRV::OpExtInst ||
3017 I.getOpcode() == SPIRV::OpFunctionCall
3018 ? I.getMF()->getRegInfo().getVRegDef(I.getOperand(1).getReg())
3019 : getRegType(I.getOperand(2).getReg(), *I.getMF(), GR);
3020 const Type *Ty = GR->getTypeForSPIRVType(FPType);
3021 Ty = Ty->isVectorTy() ? cast<VectorType>(Ty)->getElementType() : Ty;
3022
3023 // Match instruction type with the FPFastMathDefaultInfoVec.
3024 bool Emit = false;
3025 for (SPIRV::FPFastMathDefaultInfo &Elem : FPFastMathDefaultInfoVec) {
3026 if (Ty == Elem.Ty) {
3027 FMFlags = Elem.FastMathFlags;
3028 Emit = Elem.ContractionOff || Elem.SignedZeroInfNanPreserve ||
3029 Elem.FPFastMathDefault;
3030 break;
3031 }
3032 }
3033
3034 if (FMFlags == SPIRV::FPFastMathMode::None && !Emit)
3035 return Changed;
3036 }
3038 Decorate(SPIRV::Decoration::FPFastMathMode, {FMFlags});
3039 return Changed;
3040}
3041
3042static void addMBBNames(const Module &M, MachineFunctionGetter GetMF,
3044 for (const Function &F : M) {
3045 MachineFunction *MF = GetMF(F);
3046 if (!MF)
3047 continue;
3048 if (MF->getFunction()
3050 .isValid())
3051 continue;
3052 for (const auto &MBB : *MF) {
3053 if (!MBB.hasName() || MBB.empty())
3054 continue;
3055 MAI.MBBNames.emplace_back(MAI.getOrCreateMBBRegister(MBB), MBB.getName());
3056 }
3057 }
3058}
3059
3061 const Module &M,
3062 SPIRV::FPFastMathDefaultInfoMapTy &FPFastMathDefaultInfoMap,
3063 const Function *F) {
3064 auto it = FPFastMathDefaultInfoMap.find(F);
3065 if (it != FPFastMathDefaultInfoMap.end())
3066 return it->second;
3067
3068 // If the map does not contain the entry, create a new one. Initialize it to
3069 // contain all 3 elements sorted by bit width of target type: {half, float,
3070 // double}.
3071 SPIRV::FPFastMathDefaultInfoVector FPFastMathDefaultInfoVec;
3072 FPFastMathDefaultInfoVec.emplace_back(Type::getHalfTy(M.getContext()),
3073 SPIRV::FPFastMathMode::None);
3074 FPFastMathDefaultInfoVec.emplace_back(Type::getFloatTy(M.getContext()),
3075 SPIRV::FPFastMathMode::None);
3076 FPFastMathDefaultInfoVec.emplace_back(Type::getDoubleTy(M.getContext()),
3077 SPIRV::FPFastMathMode::None);
3078 return FPFastMathDefaultInfoMap[F] = std::move(FPFastMathDefaultInfoVec);
3079}
3080
3082 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec,
3083 const Type *Ty) {
3084 size_t BitWidth = Ty->getScalarSizeInBits();
3085 int Index =
3087 BitWidth);
3088 assert(Index >= 0 && Index < 3 &&
3089 "Expected FPFastMathDefaultInfo for half, float, or double");
3090 assert(FPFastMathDefaultInfoVec.size() == 3 &&
3091 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3092 return FPFastMathDefaultInfoVec[Index];
3093}
3094
3096 const Module &M,
3097 SPIRV::FPFastMathDefaultInfoMapTy &FPFastMathDefaultInfoMap,
3098 const SPIRVSubtarget &ST, const Function *OnlyF = nullptr) {
3099 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
3100 return;
3101
3102 // Store the FPFastMathDefaultInfo in the FPFastMathDefaultInfoMap.
3103 // We need the entry point (function) as the key, and the target
3104 // type and flags as the value.
3105 // We also need to check ContractionOff and SignedZeroInfNanPreserve
3106 // execution modes, as they are now deprecated and must be replaced
3107 // with FPFastMathDefaultInfo.
3108 auto Node = M.getNamedMetadata("spirv.ExecutionMode");
3109 if (!Node)
3110 return;
3111
3112 for (unsigned i = 0; i < Node->getNumOperands(); i++) {
3113 MDNode *MDN = cast<MDNode>(Node->getOperand(i));
3114 assert(MDN->getNumOperands() >= 2 && "Expected at least 2 operands");
3115 const Function *F = cast<Function>(
3116 cast<ConstantAsMetadata>(MDN->getOperand(0))->getValue());
3117 if (OnlyF && F != OnlyF)
3118 continue;
3119 const auto EM =
3121 cast<ConstantAsMetadata>(MDN->getOperand(1))->getValue())
3122 ->getZExtValue();
3123 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
3124 assert(MDN->getNumOperands() == 4 &&
3125 "Expected 4 operands for FPFastMathDefault");
3126
3127 const Type *T = cast<ValueAsMetadata>(MDN->getOperand(2))->getType();
3128 unsigned Flags =
3130 cast<ConstantAsMetadata>(MDN->getOperand(3))->getValue())
3131 ->getZExtValue();
3132 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3133 getOrCreateFPFastMathDefaultInfoVec(M, FPFastMathDefaultInfoMap, F);
3135 getFPFastMathDefaultInfo(FPFastMathDefaultInfoVec, T);
3136 Info.FastMathFlags = Flags;
3137 Info.FPFastMathDefault = true;
3138 } else if (EM == SPIRV::ExecutionMode::ContractionOff) {
3139 assert(MDN->getNumOperands() == 2 &&
3140 "Expected no operands for ContractionOff");
3141
3142 // We need to save this info for every possible FP type, i.e. {half,
3143 // float, double, fp128}.
3144 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3145 getOrCreateFPFastMathDefaultInfoVec(M, FPFastMathDefaultInfoMap, F);
3146 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3147 Info.ContractionOff = true;
3148 }
3149 } else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
3150 assert(MDN->getNumOperands() == 3 &&
3151 "Expected 1 operand for SignedZeroInfNanPreserve");
3152 unsigned TargetWidth =
3154 cast<ConstantAsMetadata>(MDN->getOperand(2))->getValue())
3155 ->getZExtValue();
3156 // We need to save this info only for the FP type with TargetWidth.
3157 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3158 getOrCreateFPFastMathDefaultInfoVec(M, FPFastMathDefaultInfoMap, F);
3161 assert(Index >= 0 && Index < 3 &&
3162 "Expected FPFastMathDefaultInfo for half, float, or double");
3163 assert(FPFastMathDefaultInfoVec.size() == 3 &&
3164 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3165 FPFastMathDefaultInfoVec[Index].SignedZeroInfNanPreserve = true;
3166 }
3167 }
3168}
3169
3173 : ST(&ST), GR(ST.getSPIRVGlobalRegistry()), TII(ST.getInstrInfo()),
3174 MAI(MAI), GetMF(GetMF) {}
3175
3177 setBaseInfo(M);
3178
3179 addMBBNames(M, GetMF, MAI);
3180 collectFPFastMathDefaults(M, MAI.FPFastMathDefaultInfoMap, *ST);
3181
3182 collectReqs(M, MAI, GetMF, *ST);
3183
3184 // Process type/const/global var/func decl instructions, number their
3185 // destination registers from 0 to N, collect Extensions and Capabilities.
3186 collectDeclarations(M);
3187
3188 // Number rest of registers from N+1 onwards.
3189 numberRegistersGlobally(M);
3190
3191 // Collect OpName, OpEntryPoint, OpDecorate etc, process other instructions.
3192 processOtherInstrs(M);
3193
3194 // If there are no entry points, we need the Linkage capability.
3195 if (MAI.MS[SPIRV::MB_EntryPoints].empty())
3196 MAI.Reqs.addCapability(SPIRV::Capability::Linkage);
3197
3198 // Set maximum ID used.
3199 GR->setBound(MAI.MaxID);
3200}
3201
3206
3208 SPIRVTargetMachine &TM =
3212 *TM.getSubtargetImpl(), MAI,
3213 [&MMI](const Function &F) { return MMI.getMachineFunction(F); })
3214 .run(M);
3215 return false;
3216}
3217
3218AnalysisKey SPIRVModuleAnalysis::Key;
3219
3222 const auto &TM = static_cast<const SPIRVTargetMachine &>(
3223 MAM.getResult<MachineModuleAnalysis>(M).getMMI().getTarget());
3225 MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
3226 Result MAI;
3227 SPIRVModuleAnalysisImpl(*TM.getSubtargetImpl(), MAI,
3228 [&FAM](const Function &F) -> MachineFunction * {
3229 MachineFunctionAnalysis::Result *MFA =
3230 FAM.getCachedResult<MachineFunctionAnalysis>(
3231 const_cast<Function &>(F));
3232 assert((MFA || F.isDeclaration()) &&
3233 "Missing MachineFunction for definition");
3234 return MFA ? &MFA->getMF() : nullptr;
3235 })
3236 .run(M);
3237 return MAI;
3238}
3239
3241 const auto &ST = MF.getSubtarget<SPIRVSubtarget>();
3242 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
3243 const SPIRVInstrInfo &TII = *ST.getInstrInfo();
3246 SPIRV::FPFastMathDefaultInfoMapTy FPFastMathDefaultInfoMap;
3247 const Function &F = MF.getFunction();
3248 collectFPFastMathDefaults(*F.getParent(), FPFastMathDefaultInfoMap, ST, &F);
3249 // Add decorations related to MI flags.
3250 bool Changed = false;
3251 for (auto &MBB : MF)
3252 for (auto &MI : make_early_inc_range(MBB))
3253 Changed |= handleMIFlagDecoration(MI, ST, TII, Reqs, GR,
3254 FPFastMathDefaultInfoMap[&F]);
3255 return Changed;
3256}
3257
3258namespace {
3259class SPIRVPrepareModuleAnalysisLegacy : public MachineFunctionPass {
3260public:
3261 static char ID;
3262 SPIRVPrepareModuleAnalysisLegacy() : MachineFunctionPass(ID) {}
3263 bool runOnMachineFunction(MachineFunction &MF) override {
3264 return prepareModuleAnalysis(MF);
3265 }
3266};
3267} // namespace
3268
3269char SPIRVPrepareModuleAnalysisLegacy::ID = 0;
3270
3271INITIALIZE_PASS(SPIRVPrepareModuleAnalysisLegacy,
3272 "spirv-prepare-module-analysis",
3273 "SPIRV prepare module analysis", false, false)
3274
3276 return new SPIRVPrepareModuleAnalysisLegacy();
3277}
3278
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
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:560
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
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:766
iterator end()
Definition DenseMap.h:686
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...
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
bool isConstantInstr(const MachineInstr &MI) 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 SPIRVInstrInfo * getInstrInfo() const override
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.
DenseMap< 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
bool requiresLongVectorEXT(unsigned NumComponents)
Definition SPIRVUtils.h:516
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.
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