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