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