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