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