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