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 MachineOperand Ins = MI.getOperand(3);
682 namespace NS = SPIRV::NonSemanticExtInst;
683 static constexpr int64_t GlobalNonSemanticDITy[] = {
684 NS::DebugSource, NS::DebugCompilationUnit, NS::DebugInfoNone,
685 NS::DebugTypeBasic, NS::DebugTypePointer};
686 bool IsGlobalDI = false;
687 for (unsigned Idx = 0; Idx < std::size(GlobalNonSemanticDITy); ++Idx)
688 IsGlobalDI |= Ins.getImm() == GlobalNonSemanticDITy[Idx];
689 if (IsGlobalDI)
690 collectOtherInstr(MI, MAI, SPIRV::MB_NonSemanticGlobalDI, IS);
691 } else if (OpCode == SPIRV::OpName || OpCode == SPIRV::OpMemberName) {
692 collectOtherInstr(MI, MAI, SPIRV::MB_DebugNames, IS);
693 } else if (OpCode == SPIRV::OpEntryPoint) {
694 collectOtherInstr(MI, MAI, SPIRV::MB_EntryPoints, IS);
695 } else if (TII->isAliasingInstr(MI)) {
696 collectOtherInstr(MI, MAI, SPIRV::MB_AliasingInsts, IS);
697 } else if (TII->isDecorationInstr(MI)) {
698 collectOtherInstr(MI, MAI, SPIRV::MB_Annotations, IS);
699 collectFuncNames(MI, &F);
700 } else if (TII->isConstantInstr(MI)) {
701 // Now OpSpecConstant*s are not in DT,
702 // but they need to be collected anyway.
703 collectOtherInstr(MI, MAI, SPIRV::MB_TypeConstVars, IS);
704 } else if (OpCode == SPIRV::OpFunction) {
705 collectFuncNames(MI, &F);
706 } else if (OpCode == SPIRV::OpTypeForwardPointer) {
707 collectOtherInstr(MI, MAI, SPIRV::MB_TypeConstVars, IS, false);
708 }
709 }
710 }
711}
712
713// Number registers in all functions globally from 0 onwards and store
714// the result in global register alias table. Some registers are already
715// numbered.
716void SPIRVModuleAnalysis::numberRegistersGlobally(const Module &M) {
717 for (const Function &F : M) {
718 if (F.isDeclaration())
719 continue;
720 MachineFunction *MF = MMI->getMachineFunction(F);
721 assert(MF);
722 for (MachineBasicBlock &MBB : *MF) {
723 for (MachineInstr &MI : MBB) {
724 for (MachineOperand &Op : MI.operands()) {
725 if (!Op.isReg())
726 continue;
727 Register Reg = Op.getReg();
728 if (MAI.hasRegisterAlias(MF, Reg))
729 continue;
730 MCRegister NewReg = MAI.getNextIDRegister();
731 MAI.setRegisterAlias(MF, Reg, NewReg);
732 }
733 if (MI.getOpcode() != SPIRV::OpExtInst)
734 continue;
735 auto Set = MI.getOperand(2).getImm();
736 auto [It, Inserted] = MAI.ExtInstSetMap.try_emplace(Set);
737 if (Inserted)
738 It->second = MAI.getNextIDRegister();
739 }
740 }
741 }
742}
743
744// RequirementHandler implementations.
746 SPIRV::OperandCategory::OperandCategory Category, uint32_t i,
747 const SPIRVSubtarget &ST) {
748 addRequirements(getSymbolicOperandRequirements(Category, i, ST, *this));
749}
750
751void SPIRV::RequirementHandler::recursiveAddCapabilities(
752 const CapabilityList &ToPrune) {
753 for (const auto &Cap : ToPrune) {
754 AllCaps.insert(Cap);
755 CapabilityList ImplicitDecls =
756 getSymbolicOperandCapabilities(OperandCategory::CapabilityOperand, Cap);
757 recursiveAddCapabilities(ImplicitDecls);
758 }
759}
760
762 for (const auto &Cap : ToAdd) {
763 bool IsNewlyInserted = AllCaps.insert(Cap).second;
764 if (!IsNewlyInserted) // Don't re-add if it's already been declared.
765 continue;
766 CapabilityList ImplicitDecls =
767 getSymbolicOperandCapabilities(OperandCategory::CapabilityOperand, Cap);
768 recursiveAddCapabilities(ImplicitDecls);
769 MinimalCaps.push_back(Cap);
770 }
771}
772
774 const SPIRV::Requirements &Req) {
775 if (!Req.IsSatisfiable)
776 report_fatal_error("Adding SPIR-V requirements this target can't satisfy.");
777
778 if (Req.Cap.has_value())
779 addCapabilities({Req.Cap.value()});
780
781 addExtensions(Req.Exts);
782
783 if (!Req.MinVer.empty()) {
784 if (!MaxVersion.empty() && Req.MinVer > MaxVersion) {
785 LLVM_DEBUG(dbgs() << "Conflicting version requirements: >= " << Req.MinVer
786 << " and <= " << MaxVersion << "\n");
787 report_fatal_error("Adding SPIR-V requirements that can't be satisfied.");
788 }
789
790 if (MinVersion.empty() || Req.MinVer > MinVersion)
791 MinVersion = Req.MinVer;
792 }
793
794 if (!Req.MaxVer.empty()) {
795 if (!MinVersion.empty() && Req.MaxVer < MinVersion) {
796 LLVM_DEBUG(dbgs() << "Conflicting version requirements: <= " << Req.MaxVer
797 << " and >= " << MinVersion << "\n");
798 report_fatal_error("Adding SPIR-V requirements that can't be satisfied.");
799 }
800
801 if (MaxVersion.empty() || Req.MaxVer < MaxVersion)
802 MaxVersion = Req.MaxVer;
803 }
804}
805
807 const SPIRVSubtarget &ST) const {
808 // Report as many errors as possible before aborting the compilation.
809 bool IsSatisfiable = true;
810 auto TargetVer = ST.getSPIRVVersion();
811
812 if (!MaxVersion.empty() && !TargetVer.empty() && MaxVersion < TargetVer) {
814 dbgs() << "Target SPIR-V version too high for required features\n"
815 << "Required max version: " << MaxVersion << " target version "
816 << TargetVer << "\n");
817 IsSatisfiable = false;
818 }
819
820 if (!MinVersion.empty() && !TargetVer.empty() && MinVersion > TargetVer) {
821 LLVM_DEBUG(dbgs() << "Target SPIR-V version too low for required features\n"
822 << "Required min version: " << MinVersion
823 << " target version " << TargetVer << "\n");
824 IsSatisfiable = false;
825 }
826
827 if (!MinVersion.empty() && !MaxVersion.empty() && MinVersion > MaxVersion) {
829 dbgs()
830 << "Version is too low for some features and too high for others.\n"
831 << "Required SPIR-V min version: " << MinVersion
832 << " required SPIR-V max version " << MaxVersion << "\n");
833 IsSatisfiable = false;
834 }
835
836 AvoidCapabilitiesSet AvoidCaps;
837 if (!ST.isShader())
838 AvoidCaps.S.insert(SPIRV::Capability::Shader);
839 else
840 AvoidCaps.S.insert(SPIRV::Capability::Kernel);
841
842 for (auto Cap : MinimalCaps) {
843 if (AvailableCaps.contains(Cap) && !AvoidCaps.S.contains(Cap))
844 continue;
845 LLVM_DEBUG(dbgs() << "Capability not supported: "
847 OperandCategory::CapabilityOperand, Cap)
848 << "\n");
849 IsSatisfiable = false;
850 }
851
852 for (auto Ext : AllExtensions) {
853 if (ST.canUseExtension(Ext))
854 continue;
855 LLVM_DEBUG(dbgs() << "Extension not supported: "
857 OperandCategory::ExtensionOperand, Ext)
858 << "\n");
859 IsSatisfiable = false;
860 }
861
862 if (!IsSatisfiable)
863 report_fatal_error("Unable to meet SPIR-V requirements for this target.");
864}
865
866// Add the given capabilities and all their implicitly defined capabilities too.
868 for (const auto Cap : ToAdd)
869 if (AvailableCaps.insert(Cap).second)
870 addAvailableCaps(getSymbolicOperandCapabilities(
871 SPIRV::OperandCategory::CapabilityOperand, Cap));
872}
873
875 const Capability::Capability ToRemove,
876 const Capability::Capability IfPresent) {
877 if (AllCaps.contains(IfPresent))
878 AllCaps.erase(ToRemove);
879}
880
881namespace llvm {
882namespace SPIRV {
883void RequirementHandler::initAvailableCapabilities(const SPIRVSubtarget &ST) {
884 // Provided by both all supported Vulkan versions and OpenCl.
885 addAvailableCaps({Capability::Shader, Capability::Linkage, Capability::Int8,
886 Capability::Int16});
887
888 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 3)))
889 addAvailableCaps({Capability::GroupNonUniform,
890 Capability::GroupNonUniformVote,
891 Capability::GroupNonUniformArithmetic,
892 Capability::GroupNonUniformBallot,
893 Capability::GroupNonUniformClustered,
894 Capability::GroupNonUniformShuffle,
895 Capability::GroupNonUniformShuffleRelative,
896 Capability::GroupNonUniformQuad});
897
898 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 6)))
899 addAvailableCaps({Capability::DotProduct, Capability::DotProductInputAll,
900 Capability::DotProductInput4x8Bit,
901 Capability::DotProductInput4x8BitPacked,
902 Capability::DemoteToHelperInvocation});
903
904 // Add capabilities enabled by extensions.
905 for (auto Extension : ST.getAllAvailableExtensions()) {
906 CapabilityList EnabledCapabilities =
908 addAvailableCaps(EnabledCapabilities);
909 }
910
911 if (!ST.isShader()) {
912 initAvailableCapabilitiesForOpenCL(ST);
913 return;
914 }
915
916 if (ST.isShader()) {
917 initAvailableCapabilitiesForVulkan(ST);
918 return;
919 }
920
921 report_fatal_error("Unimplemented environment for SPIR-V generation.");
922}
923
924void RequirementHandler::initAvailableCapabilitiesForOpenCL(
925 const SPIRVSubtarget &ST) {
926 // Add the min requirements for different OpenCL and SPIR-V versions.
927 addAvailableCaps({Capability::Addresses, Capability::Float16Buffer,
928 Capability::Kernel, Capability::Vector16,
929 Capability::Groups, Capability::GenericPointer,
930 Capability::StorageImageWriteWithoutFormat,
931 Capability::StorageImageReadWithoutFormat});
932 if (ST.hasOpenCLFullProfile())
933 addAvailableCaps({Capability::Int64, Capability::Int64Atomics});
934 if (ST.hasOpenCLImageSupport()) {
935 addAvailableCaps({Capability::ImageBasic, Capability::LiteralSampler,
936 Capability::Image1D, Capability::SampledBuffer,
937 Capability::ImageBuffer});
938 if (ST.isAtLeastOpenCLVer(VersionTuple(2, 0)))
939 addAvailableCaps({Capability::ImageReadWrite});
940 }
941 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 1)) &&
942 ST.isAtLeastOpenCLVer(VersionTuple(2, 2)))
943 addAvailableCaps({Capability::SubgroupDispatch, Capability::PipeStorage});
944 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 4)))
945 addAvailableCaps({Capability::DenormPreserve, Capability::DenormFlushToZero,
946 Capability::SignedZeroInfNanPreserve,
947 Capability::RoundingModeRTE,
948 Capability::RoundingModeRTZ});
949 // TODO: verify if this needs some checks.
950 addAvailableCaps({Capability::Float16, Capability::Float64});
951
952 // TODO: add OpenCL extensions.
953}
954
955void RequirementHandler::initAvailableCapabilitiesForVulkan(
956 const SPIRVSubtarget &ST) {
957
958 // Core in Vulkan 1.1 and earlier.
959 addAvailableCaps({Capability::Int64, Capability::Float16, Capability::Float64,
960 Capability::GroupNonUniform, Capability::Image1D,
961 Capability::SampledBuffer, Capability::ImageBuffer,
962 Capability::UniformBufferArrayDynamicIndexing,
963 Capability::SampledImageArrayDynamicIndexing,
964 Capability::StorageBufferArrayDynamicIndexing,
965 Capability::StorageImageArrayDynamicIndexing,
966 Capability::DerivativeControl, Capability::MinLod,
967 Capability::ImageQuery, Capability::ImageGatherExtended,
968 Capability::Addresses, Capability::VulkanMemoryModelKHR});
969
970 // Became core in Vulkan 1.2
971 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 5))) {
973 {Capability::ShaderNonUniformEXT, Capability::RuntimeDescriptorArrayEXT,
974 Capability::InputAttachmentArrayDynamicIndexingEXT,
975 Capability::UniformTexelBufferArrayDynamicIndexingEXT,
976 Capability::StorageTexelBufferArrayDynamicIndexingEXT,
977 Capability::UniformBufferArrayNonUniformIndexingEXT,
978 Capability::SampledImageArrayNonUniformIndexingEXT,
979 Capability::StorageBufferArrayNonUniformIndexingEXT,
980 Capability::StorageImageArrayNonUniformIndexingEXT,
981 Capability::InputAttachmentArrayNonUniformIndexingEXT,
982 Capability::UniformTexelBufferArrayNonUniformIndexingEXT,
983 Capability::StorageTexelBufferArrayNonUniformIndexingEXT});
984 }
985
986 // Became core in Vulkan 1.3
987 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 6)))
988 addAvailableCaps({Capability::StorageImageWriteWithoutFormat,
989 Capability::StorageImageReadWithoutFormat});
990}
991
992} // namespace SPIRV
993} // namespace llvm
994
995// Add the required capabilities from a decoration instruction (including
996// BuiltIns).
997static void addOpDecorateReqs(const MachineInstr &MI, unsigned DecIndex,
999 const SPIRVSubtarget &ST) {
1000 int64_t DecOp = MI.getOperand(DecIndex).getImm();
1001 auto Dec = static_cast<SPIRV::Decoration::Decoration>(DecOp);
1002 Reqs.addRequirements(getSymbolicOperandRequirements(
1003 SPIRV::OperandCategory::DecorationOperand, Dec, ST, Reqs));
1004
1005 if (Dec == SPIRV::Decoration::BuiltIn) {
1006 int64_t BuiltInOp = MI.getOperand(DecIndex + 1).getImm();
1007 auto BuiltIn = static_cast<SPIRV::BuiltIn::BuiltIn>(BuiltInOp);
1008 Reqs.addRequirements(getSymbolicOperandRequirements(
1009 SPIRV::OperandCategory::BuiltInOperand, BuiltIn, ST, Reqs));
1010 } else if (Dec == SPIRV::Decoration::LinkageAttributes) {
1011 int64_t LinkageOp = MI.getOperand(MI.getNumOperands() - 1).getImm();
1012 SPIRV::LinkageType::LinkageType LnkType =
1013 static_cast<SPIRV::LinkageType::LinkageType>(LinkageOp);
1014 if (LnkType == SPIRV::LinkageType::LinkOnceODR)
1015 Reqs.addExtension(SPIRV::Extension::SPV_KHR_linkonce_odr);
1016 } else if (Dec == SPIRV::Decoration::CacheControlLoadINTEL ||
1017 Dec == SPIRV::Decoration::CacheControlStoreINTEL) {
1018 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_cache_controls);
1019 } else if (Dec == SPIRV::Decoration::HostAccessINTEL) {
1020 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_global_variable_host_access);
1021 } else if (Dec == SPIRV::Decoration::InitModeINTEL ||
1022 Dec == SPIRV::Decoration::ImplementInRegisterMapINTEL) {
1023 Reqs.addExtension(
1024 SPIRV::Extension::SPV_INTEL_global_variable_fpga_decorations);
1025 } else if (Dec == SPIRV::Decoration::NonUniformEXT) {
1026 Reqs.addRequirements(SPIRV::Capability::ShaderNonUniformEXT);
1027 } else if (Dec == SPIRV::Decoration::FPMaxErrorDecorationINTEL) {
1028 Reqs.addRequirements(SPIRV::Capability::FPMaxErrorINTEL);
1029 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_fp_max_error);
1030 } else if (Dec == SPIRV::Decoration::FPFastMathMode) {
1031 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2)) {
1032 Reqs.addRequirements(SPIRV::Capability::FloatControls2);
1033 Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls2);
1034 }
1035 }
1036}
1037
1038// Add requirements for image handling.
1039static void addOpTypeImageReqs(const MachineInstr &MI,
1041 const SPIRVSubtarget &ST) {
1042 assert(MI.getNumOperands() >= 8 && "Insufficient operands for OpTypeImage");
1043 // The operand indices used here are based on the OpTypeImage layout, which
1044 // the MachineInstr follows as well.
1045 int64_t ImgFormatOp = MI.getOperand(7).getImm();
1046 auto ImgFormat = static_cast<SPIRV::ImageFormat::ImageFormat>(ImgFormatOp);
1047 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ImageFormatOperand,
1048 ImgFormat, ST);
1049
1050 bool IsArrayed = MI.getOperand(4).getImm() == 1;
1051 bool IsMultisampled = MI.getOperand(5).getImm() == 1;
1052 bool NoSampler = MI.getOperand(6).getImm() == 2;
1053 // Add dimension requirements.
1054 assert(MI.getOperand(2).isImm());
1055 switch (MI.getOperand(2).getImm()) {
1056 case SPIRV::Dim::DIM_1D:
1057 Reqs.addRequirements(NoSampler ? SPIRV::Capability::Image1D
1058 : SPIRV::Capability::Sampled1D);
1059 break;
1060 case SPIRV::Dim::DIM_2D:
1061 if (IsMultisampled && NoSampler)
1062 Reqs.addRequirements(SPIRV::Capability::ImageMSArray);
1063 break;
1064 case SPIRV::Dim::DIM_Cube:
1065 Reqs.addRequirements(SPIRV::Capability::Shader);
1066 if (IsArrayed)
1067 Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageCubeArray
1068 : SPIRV::Capability::SampledCubeArray);
1069 break;
1070 case SPIRV::Dim::DIM_Rect:
1071 Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageRect
1072 : SPIRV::Capability::SampledRect);
1073 break;
1074 case SPIRV::Dim::DIM_Buffer:
1075 Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageBuffer
1076 : SPIRV::Capability::SampledBuffer);
1077 break;
1078 case SPIRV::Dim::DIM_SubpassData:
1079 Reqs.addRequirements(SPIRV::Capability::InputAttachment);
1080 break;
1081 }
1082
1083 // Check if the sampled type is a 64-bit integer, which requires
1084 // Int64ImageEXT capability.
1085 assert(MI.getOperand(1).isReg());
1086 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1087 SPIRVTypeInst SampledTypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
1088 if (SampledTypeDef.isTypeIntN(64)) {
1089 Reqs.addCapability(SPIRV::Capability::Int64ImageEXT);
1090 Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_image_int64);
1091 }
1092
1093 // Has optional access qualifier.
1094 if (!ST.isShader()) {
1095 if (MI.getNumOperands() > 8 &&
1096 MI.getOperand(8).getImm() == SPIRV::AccessQualifier::ReadWrite)
1097 Reqs.addRequirements(SPIRV::Capability::ImageReadWrite);
1098 else
1099 Reqs.addRequirements(SPIRV::Capability::ImageBasic);
1100 }
1101}
1102
1103static bool isBFloat16Type(SPIRVTypeInst TypeDef) {
1104 return TypeDef && TypeDef->getNumOperands() == 3 &&
1105 TypeDef->getOpcode() == SPIRV::OpTypeFloat &&
1106 TypeDef->getOperand(1).getImm() == 16 &&
1107 TypeDef->getOperand(2).getImm() == SPIRV::FPEncoding::BFloat16KHR;
1108}
1109
1110// Add requirements for handling atomic float instructions
1111#define ATOM_FLT_REQ_EXT_MSG(ExtName) \
1112 "The atomic float instruction requires the following SPIR-V " \
1113 "extension: SPV_EXT_shader_atomic_float" ExtName
1114static void AddAtomicVectorFloatRequirements(const MachineInstr &MI,
1116 const SPIRVSubtarget &ST) {
1117 SPIRVTypeInst VecTypeDef =
1118 MI.getMF()->getRegInfo().getVRegDef(MI.getOperand(1).getReg());
1119
1120 const unsigned Rank = VecTypeDef->getOperand(2).getImm();
1121 if (Rank != 2 && Rank != 4)
1122 reportFatalUsageError("Result type of an atomic vector float instruction "
1123 "must be a 2-component or 4 component vector");
1124
1125 SPIRVTypeInst EltTypeDef =
1126 MI.getMF()->getRegInfo().getVRegDef(VecTypeDef->getOperand(1).getReg());
1127
1128 if (EltTypeDef->getOpcode() != SPIRV::OpTypeFloat ||
1129 EltTypeDef->getOperand(1).getImm() != 16)
1131 "The element type for the result type of an atomic vector float "
1132 "instruction must be a 16-bit floating-point scalar");
1133
1134 if (isBFloat16Type(EltTypeDef))
1136 "The element type for the result type of an atomic vector float "
1137 "instruction cannot be a bfloat16 scalar");
1138 if (!ST.canUseExtension(SPIRV::Extension::SPV_NV_shader_atomic_fp16_vector))
1140 "The atomic float16 vector instruction requires the following SPIR-V "
1141 "extension: SPV_NV_shader_atomic_fp16_vector");
1142
1143 Reqs.addExtension(SPIRV::Extension::SPV_NV_shader_atomic_fp16_vector);
1144 Reqs.addCapability(SPIRV::Capability::AtomicFloat16VectorNV);
1145}
1146
1147static void AddAtomicFloatRequirements(const MachineInstr &MI,
1149 const SPIRVSubtarget &ST) {
1150 assert(MI.getOperand(1).isReg() &&
1151 "Expect register operand in atomic float instruction");
1152 Register TypeReg = MI.getOperand(1).getReg();
1153 SPIRVTypeInst TypeDef = MI.getMF()->getRegInfo().getVRegDef(TypeReg);
1154
1155 if (TypeDef->getOpcode() == SPIRV::OpTypeVector)
1156 return AddAtomicVectorFloatRequirements(MI, Reqs, ST);
1157
1158 if (TypeDef->getOpcode() != SPIRV::OpTypeFloat)
1159 report_fatal_error("Result type of an atomic float instruction must be a "
1160 "floating-point type scalar");
1161
1162 unsigned BitWidth = TypeDef->getOperand(1).getImm();
1163 unsigned Op = MI.getOpcode();
1164 if (Op == SPIRV::OpAtomicFAddEXT) {
1165 if (!ST.canUseExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_add))
1167 Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_add);
1168 switch (BitWidth) {
1169 case 16:
1170 if (isBFloat16Type(TypeDef)) {
1171 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics))
1173 "The atomic bfloat16 instruction requires the following SPIR-V "
1174 "extension: SPV_INTEL_16bit_atomics",
1175 false);
1176 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics);
1177 Reqs.addCapability(SPIRV::Capability::AtomicBFloat16AddINTEL);
1178 } else {
1179 if (!ST.canUseExtension(
1180 SPIRV::Extension::SPV_EXT_shader_atomic_float16_add))
1181 report_fatal_error(ATOM_FLT_REQ_EXT_MSG("16_add"), false);
1182 Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float16_add);
1183 Reqs.addCapability(SPIRV::Capability::AtomicFloat16AddEXT);
1184 }
1185 break;
1186 case 32:
1187 Reqs.addCapability(SPIRV::Capability::AtomicFloat32AddEXT);
1188 break;
1189 case 64:
1190 Reqs.addCapability(SPIRV::Capability::AtomicFloat64AddEXT);
1191 break;
1192 default:
1194 "Unexpected floating-point type width in atomic float instruction");
1195 }
1196 } else {
1197 if (!ST.canUseExtension(
1198 SPIRV::Extension::SPV_EXT_shader_atomic_float_min_max))
1199 report_fatal_error(ATOM_FLT_REQ_EXT_MSG("_min_max"), false);
1200 Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_min_max);
1201 switch (BitWidth) {
1202 case 16:
1203 if (isBFloat16Type(TypeDef)) {
1204 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics))
1206 "The atomic bfloat16 instruction requires the following SPIR-V "
1207 "extension: SPV_INTEL_16bit_atomics",
1208 false);
1209 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics);
1210 Reqs.addCapability(SPIRV::Capability::AtomicBFloat16MinMaxINTEL);
1211 } else {
1212 Reqs.addCapability(SPIRV::Capability::AtomicFloat16MinMaxEXT);
1213 }
1214 break;
1215 case 32:
1216 Reqs.addCapability(SPIRV::Capability::AtomicFloat32MinMaxEXT);
1217 break;
1218 case 64:
1219 Reqs.addCapability(SPIRV::Capability::AtomicFloat64MinMaxEXT);
1220 break;
1221 default:
1223 "Unexpected floating-point type width in atomic float instruction");
1224 }
1225 }
1226}
1227
1228bool isUniformTexelBuffer(MachineInstr *ImageInst) {
1229 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1230 return false;
1231 uint32_t Dim = ImageInst->getOperand(2).getImm();
1232 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1233 return Dim == SPIRV::Dim::DIM_Buffer && Sampled == 1;
1234}
1235
1236bool isStorageTexelBuffer(MachineInstr *ImageInst) {
1237 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1238 return false;
1239 uint32_t Dim = ImageInst->getOperand(2).getImm();
1240 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1241 return Dim == SPIRV::Dim::DIM_Buffer && Sampled == 2;
1242}
1243
1244bool isSampledImage(MachineInstr *ImageInst) {
1245 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1246 return false;
1247 uint32_t Dim = ImageInst->getOperand(2).getImm();
1248 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1249 return Dim != SPIRV::Dim::DIM_Buffer && Sampled == 1;
1250}
1251
1252bool isInputAttachment(MachineInstr *ImageInst) {
1253 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1254 return false;
1255 uint32_t Dim = ImageInst->getOperand(2).getImm();
1256 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1257 return Dim == SPIRV::Dim::DIM_SubpassData && Sampled == 2;
1258}
1259
1260bool isStorageImage(MachineInstr *ImageInst) {
1261 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1262 return false;
1263 uint32_t Dim = ImageInst->getOperand(2).getImm();
1264 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1265 return Dim != SPIRV::Dim::DIM_Buffer && Sampled == 2;
1266}
1267
1268bool isCombinedImageSampler(MachineInstr *SampledImageInst) {
1269 if (SampledImageInst->getOpcode() != SPIRV::OpTypeSampledImage)
1270 return false;
1271
1272 const MachineRegisterInfo &MRI = SampledImageInst->getMF()->getRegInfo();
1273 Register ImageReg = SampledImageInst->getOperand(1).getReg();
1274 auto *ImageInst = MRI.getUniqueVRegDef(ImageReg);
1275 return isSampledImage(ImageInst);
1276}
1277
1278bool hasNonUniformDecoration(Register Reg, const MachineRegisterInfo &MRI) {
1279 for (const auto &MI : MRI.reg_instructions(Reg)) {
1280 if (MI.getOpcode() != SPIRV::OpDecorate)
1281 continue;
1282
1283 uint32_t Dec = MI.getOperand(1).getImm();
1284 if (Dec == SPIRV::Decoration::NonUniformEXT)
1285 return true;
1286 }
1287 return false;
1288}
1289
1290void addOpAccessChainReqs(const MachineInstr &Instr,
1292 const SPIRVSubtarget &Subtarget) {
1293 const MachineRegisterInfo &MRI = Instr.getMF()->getRegInfo();
1294 // Get the result type. If it is an image type, then the shader uses
1295 // descriptor indexing. The appropriate capabilities will be added based
1296 // on the specifics of the image.
1297 Register ResTypeReg = Instr.getOperand(1).getReg();
1298 MachineInstr *ResTypeInst = MRI.getUniqueVRegDef(ResTypeReg);
1299
1300 assert(ResTypeInst->getOpcode() == SPIRV::OpTypePointer);
1301 uint32_t StorageClass = ResTypeInst->getOperand(1).getImm();
1302 if (StorageClass != SPIRV::StorageClass::StorageClass::UniformConstant &&
1303 StorageClass != SPIRV::StorageClass::StorageClass::Uniform &&
1304 StorageClass != SPIRV::StorageClass::StorageClass::StorageBuffer) {
1305 return;
1306 }
1307
1308 bool IsNonUniform =
1309 hasNonUniformDecoration(Instr.getOperand(0).getReg(), MRI);
1310
1311 auto FirstIndexReg = Instr.getOperand(3).getReg();
1312 bool FirstIndexIsConstant =
1313 Subtarget.getInstrInfo()->isConstantInstr(*MRI.getVRegDef(FirstIndexReg));
1314
1315 if (StorageClass == SPIRV::StorageClass::StorageClass::StorageBuffer) {
1316 if (IsNonUniform)
1317 Handler.addRequirements(
1318 SPIRV::Capability::StorageBufferArrayNonUniformIndexingEXT);
1319 else if (!FirstIndexIsConstant)
1320 Handler.addRequirements(
1321 SPIRV::Capability::StorageBufferArrayDynamicIndexing);
1322 return;
1323 }
1324
1325 Register PointeeTypeReg = ResTypeInst->getOperand(2).getReg();
1326 MachineInstr *PointeeType = MRI.getUniqueVRegDef(PointeeTypeReg);
1327 if (PointeeType->getOpcode() != SPIRV::OpTypeImage &&
1328 PointeeType->getOpcode() != SPIRV::OpTypeSampledImage &&
1329 PointeeType->getOpcode() != SPIRV::OpTypeSampler) {
1330 return;
1331 }
1332
1333 if (isUniformTexelBuffer(PointeeType)) {
1334 if (IsNonUniform)
1335 Handler.addRequirements(
1336 SPIRV::Capability::UniformTexelBufferArrayNonUniformIndexingEXT);
1337 else if (!FirstIndexIsConstant)
1338 Handler.addRequirements(
1339 SPIRV::Capability::UniformTexelBufferArrayDynamicIndexingEXT);
1340 } else if (isInputAttachment(PointeeType)) {
1341 if (IsNonUniform)
1342 Handler.addRequirements(
1343 SPIRV::Capability::InputAttachmentArrayNonUniformIndexingEXT);
1344 else if (!FirstIndexIsConstant)
1345 Handler.addRequirements(
1346 SPIRV::Capability::InputAttachmentArrayDynamicIndexingEXT);
1347 } else if (isStorageTexelBuffer(PointeeType)) {
1348 if (IsNonUniform)
1349 Handler.addRequirements(
1350 SPIRV::Capability::StorageTexelBufferArrayNonUniformIndexingEXT);
1351 else if (!FirstIndexIsConstant)
1352 Handler.addRequirements(
1353 SPIRV::Capability::StorageTexelBufferArrayDynamicIndexingEXT);
1354 } else if (isSampledImage(PointeeType) ||
1355 isCombinedImageSampler(PointeeType) ||
1356 PointeeType->getOpcode() == SPIRV::OpTypeSampler) {
1357 if (IsNonUniform)
1358 Handler.addRequirements(
1359 SPIRV::Capability::SampledImageArrayNonUniformIndexingEXT);
1360 else if (!FirstIndexIsConstant)
1361 Handler.addRequirements(
1362 SPIRV::Capability::SampledImageArrayDynamicIndexing);
1363 } else if (isStorageImage(PointeeType)) {
1364 if (IsNonUniform)
1365 Handler.addRequirements(
1366 SPIRV::Capability::StorageImageArrayNonUniformIndexingEXT);
1367 else if (!FirstIndexIsConstant)
1368 Handler.addRequirements(
1369 SPIRV::Capability::StorageImageArrayDynamicIndexing);
1370 }
1371}
1372
1373static bool isImageTypeWithUnknownFormat(SPIRVTypeInst TypeInst) {
1374 if (TypeInst->getOpcode() != SPIRV::OpTypeImage)
1375 return false;
1376 assert(TypeInst->getOperand(7).isImm() && "The image format must be an imm.");
1377 return TypeInst->getOperand(7).getImm() == 0;
1378}
1379
1380static void AddDotProductRequirements(const MachineInstr &MI,
1382 const SPIRVSubtarget &ST) {
1383 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product))
1384 Reqs.addExtension(SPIRV::Extension::SPV_KHR_integer_dot_product);
1385 Reqs.addCapability(SPIRV::Capability::DotProduct);
1386
1387 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1388 assert(MI.getOperand(2).isReg() && "Unexpected operand in dot");
1389 // We do not consider what the previous instruction is. This is just used
1390 // to get the input register and to check the type.
1391 const MachineInstr *Input = MRI.getVRegDef(MI.getOperand(2).getReg());
1392 assert(Input->getOperand(1).isReg() && "Unexpected operand in dot input");
1393 Register InputReg = Input->getOperand(1).getReg();
1394
1395 SPIRVTypeInst TypeDef = MRI.getVRegDef(InputReg);
1396 if (TypeDef->getOpcode() == SPIRV::OpTypeInt) {
1397 assert(TypeDef->getOperand(1).getImm() == 32);
1398 Reqs.addCapability(SPIRV::Capability::DotProductInput4x8BitPacked);
1399 } else if (TypeDef->getOpcode() == SPIRV::OpTypeVector) {
1400 SPIRVTypeInst ScalarTypeDef =
1401 MRI.getVRegDef(TypeDef->getOperand(1).getReg());
1402 assert(ScalarTypeDef->getOpcode() == SPIRV::OpTypeInt);
1403 if (ScalarTypeDef->getOperand(1).getImm() == 8) {
1404 assert(TypeDef->getOperand(2).getImm() == 4 &&
1405 "Dot operand of 8-bit integer type requires 4 components");
1406 Reqs.addCapability(SPIRV::Capability::DotProductInput4x8Bit);
1407 } else {
1408 Reqs.addCapability(SPIRV::Capability::DotProductInputAll);
1409 }
1410 }
1411}
1412
1413void addPrintfRequirements(const MachineInstr &MI,
1415 const SPIRVSubtarget &ST) {
1416 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
1417 SPIRVTypeInst PtrType = GR->getSPIRVTypeForVReg(MI.getOperand(4).getReg());
1418 if (PtrType) {
1419 MachineOperand ASOp = PtrType->getOperand(1);
1420 if (ASOp.isImm()) {
1421 unsigned AddrSpace = ASOp.getImm();
1422 if (AddrSpace != SPIRV::StorageClass::UniformConstant) {
1423 if (!ST.canUseExtension(
1425 SPV_EXT_relaxed_printf_string_address_space)) {
1426 report_fatal_error("SPV_EXT_relaxed_printf_string_address_space is "
1427 "required because printf uses a format string not "
1428 "in constant address space.",
1429 false);
1430 }
1431 Reqs.addExtension(
1432 SPIRV::Extension::SPV_EXT_relaxed_printf_string_address_space);
1433 }
1434 }
1435 }
1436}
1437
1438static void addImageOperandReqs(const MachineInstr &MI,
1440 const SPIRVSubtarget &ST, unsigned OpIdx) {
1441 if (MI.getNumOperands() <= OpIdx)
1442 return;
1443 uint32_t Mask = MI.getOperand(OpIdx).getImm();
1444 for (uint32_t I = 0; I < 32; ++I)
1445 if (Mask & (1U << I))
1446 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ImageOperandOperand,
1447 1U << I, ST);
1448}
1449
1450void addInstrRequirements(const MachineInstr &MI,
1452 const SPIRVSubtarget &ST) {
1453 SPIRV::RequirementHandler &Reqs = MAI.Reqs;
1454 unsigned Op = MI.getOpcode();
1455 switch (Op) {
1456 case SPIRV::OpMemoryModel: {
1457 int64_t Addr = MI.getOperand(0).getImm();
1458 Reqs.getAndAddRequirements(SPIRV::OperandCategory::AddressingModelOperand,
1459 Addr, ST);
1460 int64_t Mem = MI.getOperand(1).getImm();
1461 Reqs.getAndAddRequirements(SPIRV::OperandCategory::MemoryModelOperand, Mem,
1462 ST);
1463 break;
1464 }
1465 case SPIRV::OpEntryPoint: {
1466 int64_t Exe = MI.getOperand(0).getImm();
1467 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ExecutionModelOperand,
1468 Exe, ST);
1469 break;
1470 }
1471 case SPIRV::OpExecutionMode:
1472 case SPIRV::OpExecutionModeId: {
1473 int64_t Exe = MI.getOperand(1).getImm();
1474 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ExecutionModeOperand,
1475 Exe, ST);
1476 break;
1477 }
1478 case SPIRV::OpTypeMatrix:
1479 Reqs.addCapability(SPIRV::Capability::Matrix);
1480 break;
1481 case SPIRV::OpTypeInt: {
1482 unsigned BitWidth = MI.getOperand(1).getImm();
1483 if (BitWidth == 64)
1484 Reqs.addCapability(SPIRV::Capability::Int64);
1485 else if (BitWidth == 16)
1486 Reqs.addCapability(SPIRV::Capability::Int16);
1487 else if (BitWidth == 8)
1488 Reqs.addCapability(SPIRV::Capability::Int8);
1489 else if (BitWidth == 4 &&
1490 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_int4)) {
1491 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_int4);
1492 Reqs.addCapability(SPIRV::Capability::Int4TypeINTEL);
1493 } else if (BitWidth != 32) {
1494 if (!ST.canUseExtension(
1495 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers))
1497 "OpTypeInt type with a width other than 8, 16, 32 or 64 bits "
1498 "requires the following SPIR-V extension: "
1499 "SPV_ALTERA_arbitrary_precision_integers");
1500 Reqs.addExtension(
1501 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers);
1502 Reqs.addCapability(SPIRV::Capability::ArbitraryPrecisionIntegersALTERA);
1503 }
1504 break;
1505 }
1506 case SPIRV::OpDot: {
1507 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1508 SPIRVTypeInst TypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
1509 if (isBFloat16Type(TypeDef))
1510 Reqs.addCapability(SPIRV::Capability::BFloat16DotProductKHR);
1511 break;
1512 }
1513 case SPIRV::OpTypeFloat: {
1514 unsigned BitWidth = MI.getOperand(1).getImm();
1515 if (BitWidth == 64)
1516 Reqs.addCapability(SPIRV::Capability::Float64);
1517 else if (BitWidth == 16) {
1518 if (isBFloat16Type(&MI)) {
1519 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_bfloat16))
1520 report_fatal_error("OpTypeFloat type with bfloat requires the "
1521 "following SPIR-V extension: SPV_KHR_bfloat16",
1522 false);
1523 Reqs.addExtension(SPIRV::Extension::SPV_KHR_bfloat16);
1524 Reqs.addCapability(SPIRV::Capability::BFloat16TypeKHR);
1525 } else {
1526 Reqs.addCapability(SPIRV::Capability::Float16);
1527 }
1528 }
1529 break;
1530 }
1531 case SPIRV::OpTypeVector: {
1532 unsigned NumComponents = MI.getOperand(2).getImm();
1533 if (NumComponents == 8 || NumComponents == 16)
1534 Reqs.addCapability(SPIRV::Capability::Vector16);
1535
1536 assert(MI.getOperand(1).isReg());
1537 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1538 SPIRVTypeInst ElemTypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
1539 if (ElemTypeDef->getOpcode() == SPIRV::OpTypePointer &&
1540 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
1541 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_masked_gather_scatter);
1542 Reqs.addCapability(SPIRV::Capability::MaskedGatherScatterINTEL);
1543 }
1544 break;
1545 }
1546 case SPIRV::OpTypePointer: {
1547 auto SC = MI.getOperand(1).getImm();
1548 Reqs.getAndAddRequirements(SPIRV::OperandCategory::StorageClassOperand, SC,
1549 ST);
1550 // If it's a type of pointer to float16 targeting OpenCL, add Float16Buffer
1551 // capability.
1552 if (ST.isShader())
1553 break;
1554 assert(MI.getOperand(2).isReg());
1555 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1556 SPIRVTypeInst TypeDef = MRI.getVRegDef(MI.getOperand(2).getReg());
1557 if ((TypeDef->getNumOperands() == 2) &&
1558 (TypeDef->getOpcode() == SPIRV::OpTypeFloat) &&
1559 (TypeDef->getOperand(1).getImm() == 16))
1560 Reqs.addCapability(SPIRV::Capability::Float16Buffer);
1561 break;
1562 }
1563 case SPIRV::OpExtInst: {
1564 if (MI.getOperand(2).getImm() ==
1565 static_cast<int64_t>(
1566 SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100)) {
1567 Reqs.addExtension(SPIRV::Extension::SPV_KHR_non_semantic_info);
1568 break;
1569 }
1570 if (MI.getOperand(3).getImm() ==
1571 static_cast<int64_t>(SPIRV::OpenCLExtInst::printf)) {
1572 addPrintfRequirements(MI, Reqs, ST);
1573 break;
1574 }
1575 // TODO: handle bfloat16 extended instructions when
1576 // SPV_INTEL_bfloat16_arithmetic is enabled.
1577 break;
1578 }
1579 case SPIRV::OpAliasDomainDeclINTEL:
1580 case SPIRV::OpAliasScopeDeclINTEL:
1581 case SPIRV::OpAliasScopeListDeclINTEL: {
1582 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing);
1583 Reqs.addCapability(SPIRV::Capability::MemoryAccessAliasingINTEL);
1584 break;
1585 }
1586 case SPIRV::OpBitReverse:
1587 case SPIRV::OpBitFieldInsert:
1588 case SPIRV::OpBitFieldSExtract:
1589 case SPIRV::OpBitFieldUExtract:
1590 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions)) {
1591 Reqs.addCapability(SPIRV::Capability::Shader);
1592 break;
1593 }
1594 Reqs.addExtension(SPIRV::Extension::SPV_KHR_bit_instructions);
1595 Reqs.addCapability(SPIRV::Capability::BitInstructions);
1596 break;
1597 case SPIRV::OpTypeRuntimeArray:
1598 Reqs.addCapability(SPIRV::Capability::Shader);
1599 break;
1600 case SPIRV::OpTypeOpaque:
1601 case SPIRV::OpTypeEvent:
1602 Reqs.addCapability(SPIRV::Capability::Kernel);
1603 break;
1604 case SPIRV::OpTypePipe:
1605 case SPIRV::OpTypeReserveId:
1606 Reqs.addCapability(SPIRV::Capability::Pipes);
1607 break;
1608 case SPIRV::OpTypeDeviceEvent:
1609 case SPIRV::OpTypeQueue:
1610 case SPIRV::OpBuildNDRange:
1611 Reqs.addCapability(SPIRV::Capability::DeviceEnqueue);
1612 break;
1613 case SPIRV::OpDecorate:
1614 case SPIRV::OpDecorateId:
1615 case SPIRV::OpDecorateString:
1616 addOpDecorateReqs(MI, 1, Reqs, ST);
1617 break;
1618 case SPIRV::OpMemberDecorate:
1619 case SPIRV::OpMemberDecorateString:
1620 addOpDecorateReqs(MI, 2, Reqs, ST);
1621 break;
1622 case SPIRV::OpInBoundsPtrAccessChain:
1623 Reqs.addCapability(SPIRV::Capability::Addresses);
1624 break;
1625 case SPIRV::OpConstantSampler:
1626 Reqs.addCapability(SPIRV::Capability::LiteralSampler);
1627 break;
1628 case SPIRV::OpInBoundsAccessChain:
1629 case SPIRV::OpAccessChain:
1630 addOpAccessChainReqs(MI, Reqs, ST);
1631 break;
1632 case SPIRV::OpTypeImage:
1633 addOpTypeImageReqs(MI, Reqs, ST);
1634 break;
1635 case SPIRV::OpTypeSampler:
1636 if (!ST.isShader()) {
1637 Reqs.addCapability(SPIRV::Capability::ImageBasic);
1638 }
1639 break;
1640 case SPIRV::OpTypeForwardPointer:
1641 // TODO: check if it's OpenCL's kernel.
1642 Reqs.addCapability(SPIRV::Capability::Addresses);
1643 break;
1644 case SPIRV::OpAtomicFlagTestAndSet:
1645 case SPIRV::OpAtomicLoad:
1646 case SPIRV::OpAtomicStore:
1647 case SPIRV::OpAtomicExchange:
1648 case SPIRV::OpAtomicCompareExchange:
1649 case SPIRV::OpAtomicIIncrement:
1650 case SPIRV::OpAtomicIDecrement:
1651 case SPIRV::OpAtomicIAdd:
1652 case SPIRV::OpAtomicISub:
1653 case SPIRV::OpAtomicUMin:
1654 case SPIRV::OpAtomicUMax:
1655 case SPIRV::OpAtomicSMin:
1656 case SPIRV::OpAtomicSMax:
1657 case SPIRV::OpAtomicAnd:
1658 case SPIRV::OpAtomicOr:
1659 case SPIRV::OpAtomicXor: {
1660 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1661 const MachineInstr *InstrPtr = &MI;
1662 if (Op == SPIRV::OpAtomicStore) {
1663 assert(MI.getOperand(3).isReg());
1664 InstrPtr = MRI.getVRegDef(MI.getOperand(3).getReg());
1665 assert(InstrPtr && "Unexpected type instruction for OpAtomicStore");
1666 }
1667 assert(InstrPtr->getOperand(1).isReg() && "Unexpected operand in atomic");
1668 Register TypeReg = InstrPtr->getOperand(1).getReg();
1669 SPIRVTypeInst TypeDef = MRI.getVRegDef(TypeReg);
1670
1671 if (TypeDef->getOpcode() == SPIRV::OpTypeInt) {
1672 unsigned BitWidth = TypeDef->getOperand(1).getImm();
1673 if (BitWidth == 64)
1674 Reqs.addCapability(SPIRV::Capability::Int64Atomics);
1675 else if (BitWidth == 16) {
1676 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics))
1678 "16-bit integer atomic operations require the following SPIR-V "
1679 "extension: SPV_INTEL_16bit_atomics",
1680 false);
1681 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics);
1682 switch (Op) {
1683 case SPIRV::OpAtomicLoad:
1684 case SPIRV::OpAtomicStore:
1685 case SPIRV::OpAtomicExchange:
1686 case SPIRV::OpAtomicCompareExchange:
1687 case SPIRV::OpAtomicCompareExchangeWeak:
1688 Reqs.addCapability(
1689 SPIRV::Capability::AtomicInt16CompareExchangeINTEL);
1690 break;
1691 default:
1692 Reqs.addCapability(SPIRV::Capability::Int16AtomicsINTEL);
1693 break;
1694 }
1695 }
1696 } else if (isBFloat16Type(TypeDef)) {
1697 if (is_contained({SPIRV::OpAtomicLoad, SPIRV::OpAtomicStore,
1698 SPIRV::OpAtomicExchange},
1699 Op)) {
1700 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics))
1702 "The atomic bfloat16 instruction requires the following SPIR-V "
1703 "extension: SPV_INTEL_16bit_atomics",
1704 false);
1705 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics);
1706 Reqs.addCapability(SPIRV::Capability::AtomicBFloat16LoadStoreINTEL);
1707 }
1708 }
1709 break;
1710 }
1711 case SPIRV::OpGroupNonUniformIAdd:
1712 case SPIRV::OpGroupNonUniformFAdd:
1713 case SPIRV::OpGroupNonUniformIMul:
1714 case SPIRV::OpGroupNonUniformFMul:
1715 case SPIRV::OpGroupNonUniformSMin:
1716 case SPIRV::OpGroupNonUniformUMin:
1717 case SPIRV::OpGroupNonUniformFMin:
1718 case SPIRV::OpGroupNonUniformSMax:
1719 case SPIRV::OpGroupNonUniformUMax:
1720 case SPIRV::OpGroupNonUniformFMax:
1721 case SPIRV::OpGroupNonUniformBitwiseAnd:
1722 case SPIRV::OpGroupNonUniformBitwiseOr:
1723 case SPIRV::OpGroupNonUniformBitwiseXor:
1724 case SPIRV::OpGroupNonUniformLogicalAnd:
1725 case SPIRV::OpGroupNonUniformLogicalOr:
1726 case SPIRV::OpGroupNonUniformLogicalXor: {
1727 assert(MI.getOperand(3).isImm());
1728 int64_t GroupOp = MI.getOperand(3).getImm();
1729 switch (GroupOp) {
1730 case SPIRV::GroupOperation::Reduce:
1731 case SPIRV::GroupOperation::InclusiveScan:
1732 case SPIRV::GroupOperation::ExclusiveScan:
1733 Reqs.addCapability(SPIRV::Capability::GroupNonUniformArithmetic);
1734 break;
1735 case SPIRV::GroupOperation::ClusteredReduce:
1736 Reqs.addCapability(SPIRV::Capability::GroupNonUniformClustered);
1737 break;
1738 case SPIRV::GroupOperation::PartitionedReduceNV:
1739 case SPIRV::GroupOperation::PartitionedInclusiveScanNV:
1740 case SPIRV::GroupOperation::PartitionedExclusiveScanNV:
1741 Reqs.addCapability(SPIRV::Capability::GroupNonUniformPartitionedNV);
1742 break;
1743 }
1744 break;
1745 }
1746 case SPIRV::OpGroupNonUniformQuadSwap:
1747 Reqs.addCapability(SPIRV::Capability::GroupNonUniformQuad);
1748 break;
1749 case SPIRV::OpImageQueryLod:
1750 Reqs.addCapability(SPIRV::Capability::ImageQuery);
1751 break;
1752 case SPIRV::OpImageQuerySize:
1753 case SPIRV::OpImageQuerySizeLod:
1754 case SPIRV::OpImageQueryLevels:
1755 case SPIRV::OpImageQuerySamples:
1756 if (ST.isShader())
1757 Reqs.addCapability(SPIRV::Capability::ImageQuery);
1758 break;
1759 case SPIRV::OpImageQueryFormat: {
1760 Register ResultReg = MI.getOperand(0).getReg();
1761 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1762 static const unsigned CompareOps[] = {
1763 SPIRV::OpIEqual, SPIRV::OpINotEqual,
1764 SPIRV::OpUGreaterThan, SPIRV::OpUGreaterThanEqual,
1765 SPIRV::OpULessThan, SPIRV::OpULessThanEqual,
1766 SPIRV::OpSGreaterThan, SPIRV::OpSGreaterThanEqual,
1767 SPIRV::OpSLessThan, SPIRV::OpSLessThanEqual};
1768
1769 auto CheckAndAddExtension = [&](int64_t ImmVal) {
1770 if (ImmVal == 4323 || ImmVal == 4324) {
1771 if (ST.canUseExtension(SPIRV::Extension::SPV_EXT_image_raw10_raw12))
1772 Reqs.addExtension(SPIRV::Extension::SPV_EXT_image_raw10_raw12);
1773 else
1774 report_fatal_error("This requires the "
1775 "SPV_EXT_image_raw10_raw12 extension");
1776 }
1777 };
1778
1779 for (MachineInstr &UseInst : MRI.use_instructions(ResultReg)) {
1780 unsigned Opc = UseInst.getOpcode();
1781
1782 if (Opc == SPIRV::OpSwitch) {
1783 for (const MachineOperand &Op : UseInst.operands())
1784 if (Op.isImm())
1785 CheckAndAddExtension(Op.getImm());
1786 } else if (llvm::is_contained(CompareOps, Opc)) {
1787 for (unsigned i = 1; i < UseInst.getNumOperands(); ++i) {
1788 Register UseReg = UseInst.getOperand(i).getReg();
1789 MachineInstr *ConstInst = MRI.getVRegDef(UseReg);
1790 if (ConstInst && ConstInst->getOpcode() == SPIRV::OpConstantI) {
1791 int64_t ImmVal = ConstInst->getOperand(2).getImm();
1792 if (ImmVal)
1793 CheckAndAddExtension(ImmVal);
1794 }
1795 }
1796 }
1797 }
1798 break;
1799 }
1800
1801 case SPIRV::OpGroupNonUniformShuffle:
1802 case SPIRV::OpGroupNonUniformShuffleXor:
1803 Reqs.addCapability(SPIRV::Capability::GroupNonUniformShuffle);
1804 break;
1805 case SPIRV::OpGroupNonUniformShuffleUp:
1806 case SPIRV::OpGroupNonUniformShuffleDown:
1807 Reqs.addCapability(SPIRV::Capability::GroupNonUniformShuffleRelative);
1808 break;
1809 case SPIRV::OpGroupAll:
1810 case SPIRV::OpGroupAny:
1811 case SPIRV::OpGroupBroadcast:
1812 case SPIRV::OpGroupIAdd:
1813 case SPIRV::OpGroupFAdd:
1814 case SPIRV::OpGroupFMin:
1815 case SPIRV::OpGroupUMin:
1816 case SPIRV::OpGroupSMin:
1817 case SPIRV::OpGroupFMax:
1818 case SPIRV::OpGroupUMax:
1819 case SPIRV::OpGroupSMax:
1820 Reqs.addCapability(SPIRV::Capability::Groups);
1821 break;
1822 case SPIRV::OpGroupNonUniformElect:
1823 Reqs.addCapability(SPIRV::Capability::GroupNonUniform);
1824 break;
1825 case SPIRV::OpGroupNonUniformAll:
1826 case SPIRV::OpGroupNonUniformAny:
1827 case SPIRV::OpGroupNonUniformAllEqual:
1828 Reqs.addCapability(SPIRV::Capability::GroupNonUniformVote);
1829 break;
1830 case SPIRV::OpGroupNonUniformBroadcast:
1831 case SPIRV::OpGroupNonUniformBroadcastFirst:
1832 case SPIRV::OpGroupNonUniformBallot:
1833 case SPIRV::OpGroupNonUniformInverseBallot:
1834 case SPIRV::OpGroupNonUniformBallotBitExtract:
1835 case SPIRV::OpGroupNonUniformBallotBitCount:
1836 case SPIRV::OpGroupNonUniformBallotFindLSB:
1837 case SPIRV::OpGroupNonUniformBallotFindMSB:
1838 Reqs.addCapability(SPIRV::Capability::GroupNonUniformBallot);
1839 break;
1840 case SPIRV::OpSubgroupShuffleINTEL:
1841 case SPIRV::OpSubgroupShuffleDownINTEL:
1842 case SPIRV::OpSubgroupShuffleUpINTEL:
1843 case SPIRV::OpSubgroupShuffleXorINTEL:
1844 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
1845 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
1846 Reqs.addCapability(SPIRV::Capability::SubgroupShuffleINTEL);
1847 }
1848 break;
1849 case SPIRV::OpSubgroupBlockReadINTEL:
1850 case SPIRV::OpSubgroupBlockWriteINTEL:
1851 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
1852 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
1853 Reqs.addCapability(SPIRV::Capability::SubgroupBufferBlockIOINTEL);
1854 }
1855 break;
1856 case SPIRV::OpSubgroupImageBlockReadINTEL:
1857 case SPIRV::OpSubgroupImageBlockWriteINTEL:
1858 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
1859 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
1860 Reqs.addCapability(SPIRV::Capability::SubgroupImageBlockIOINTEL);
1861 }
1862 break;
1863 case SPIRV::OpSubgroupImageMediaBlockReadINTEL:
1864 case SPIRV::OpSubgroupImageMediaBlockWriteINTEL:
1865 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_media_block_io)) {
1866 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_media_block_io);
1867 Reqs.addCapability(SPIRV::Capability::SubgroupImageMediaBlockIOINTEL);
1868 }
1869 break;
1870 case SPIRV::OpAssumeTrueKHR:
1871 case SPIRV::OpExpectKHR:
1872 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) {
1873 Reqs.addExtension(SPIRV::Extension::SPV_KHR_expect_assume);
1874 Reqs.addCapability(SPIRV::Capability::ExpectAssumeKHR);
1875 }
1876 break;
1877 case SPIRV::OpFmaKHR:
1878 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_fma)) {
1879 Reqs.addExtension(SPIRV::Extension::SPV_KHR_fma);
1880 Reqs.addCapability(SPIRV::Capability::FmaKHR);
1881 }
1882 break;
1883 case SPIRV::OpPtrCastToCrossWorkgroupINTEL:
1884 case SPIRV::OpCrossWorkgroupCastToPtrINTEL:
1885 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes)) {
1886 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes);
1887 Reqs.addCapability(SPIRV::Capability::USMStorageClassesINTEL);
1888 }
1889 break;
1890 case SPIRV::OpConstantFunctionPointerINTEL:
1891 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)) {
1892 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
1893 Reqs.addCapability(SPIRV::Capability::FunctionPointersINTEL);
1894 }
1895 break;
1896 case SPIRV::OpGroupNonUniformRotateKHR:
1897 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_subgroup_rotate))
1898 report_fatal_error("OpGroupNonUniformRotateKHR instruction requires the "
1899 "following SPIR-V extension: SPV_KHR_subgroup_rotate",
1900 false);
1901 Reqs.addExtension(SPIRV::Extension::SPV_KHR_subgroup_rotate);
1902 Reqs.addCapability(SPIRV::Capability::GroupNonUniformRotateKHR);
1903 Reqs.addCapability(SPIRV::Capability::GroupNonUniform);
1904 break;
1905 case SPIRV::OpFixedCosALTERA:
1906 case SPIRV::OpFixedSinALTERA:
1907 case SPIRV::OpFixedCosPiALTERA:
1908 case SPIRV::OpFixedSinPiALTERA:
1909 case SPIRV::OpFixedExpALTERA:
1910 case SPIRV::OpFixedLogALTERA:
1911 case SPIRV::OpFixedRecipALTERA:
1912 case SPIRV::OpFixedSqrtALTERA:
1913 case SPIRV::OpFixedSinCosALTERA:
1914 case SPIRV::OpFixedSinCosPiALTERA:
1915 case SPIRV::OpFixedRsqrtALTERA:
1916 if (!ST.canUseExtension(
1917 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_fixed_point))
1918 report_fatal_error("This instruction requires the "
1919 "following SPIR-V extension: "
1920 "SPV_ALTERA_arbitrary_precision_fixed_point",
1921 false);
1922 Reqs.addExtension(
1923 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_fixed_point);
1924 Reqs.addCapability(SPIRV::Capability::ArbitraryPrecisionFixedPointALTERA);
1925 break;
1926 case SPIRV::OpGroupIMulKHR:
1927 case SPIRV::OpGroupFMulKHR:
1928 case SPIRV::OpGroupBitwiseAndKHR:
1929 case SPIRV::OpGroupBitwiseOrKHR:
1930 case SPIRV::OpGroupBitwiseXorKHR:
1931 case SPIRV::OpGroupLogicalAndKHR:
1932 case SPIRV::OpGroupLogicalOrKHR:
1933 case SPIRV::OpGroupLogicalXorKHR:
1934 if (ST.canUseExtension(
1935 SPIRV::Extension::SPV_KHR_uniform_group_instructions)) {
1936 Reqs.addExtension(SPIRV::Extension::SPV_KHR_uniform_group_instructions);
1937 Reqs.addCapability(SPIRV::Capability::GroupUniformArithmeticKHR);
1938 }
1939 break;
1940 case SPIRV::OpReadClockKHR:
1941 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_shader_clock))
1942 report_fatal_error("OpReadClockKHR instruction requires the "
1943 "following SPIR-V extension: SPV_KHR_shader_clock",
1944 false);
1945 Reqs.addExtension(SPIRV::Extension::SPV_KHR_shader_clock);
1946 Reqs.addCapability(SPIRV::Capability::ShaderClockKHR);
1947 break;
1948 case SPIRV::OpFunctionPointerCallINTEL:
1949 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)) {
1950 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
1951 Reqs.addCapability(SPIRV::Capability::FunctionPointersINTEL);
1952 }
1953 break;
1954 case SPIRV::OpAtomicFAddEXT:
1955 case SPIRV::OpAtomicFMinEXT:
1956 case SPIRV::OpAtomicFMaxEXT:
1957 AddAtomicFloatRequirements(MI, Reqs, ST);
1958 break;
1959 case SPIRV::OpConvertBF16ToFINTEL:
1960 case SPIRV::OpConvertFToBF16INTEL:
1961 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bfloat16_conversion)) {
1962 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_conversion);
1963 Reqs.addCapability(SPIRV::Capability::BFloat16ConversionINTEL);
1964 }
1965 break;
1966 case SPIRV::OpRoundFToTF32INTEL:
1967 if (ST.canUseExtension(
1968 SPIRV::Extension::SPV_INTEL_tensor_float32_conversion)) {
1969 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_tensor_float32_conversion);
1970 Reqs.addCapability(SPIRV::Capability::TensorFloat32RoundingINTEL);
1971 }
1972 break;
1973 case SPIRV::OpVariableLengthArrayINTEL:
1974 case SPIRV::OpSaveMemoryINTEL:
1975 case SPIRV::OpRestoreMemoryINTEL:
1976 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array)) {
1977 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_variable_length_array);
1978 Reqs.addCapability(SPIRV::Capability::VariableLengthArrayINTEL);
1979 }
1980 break;
1981 case SPIRV::OpAsmTargetINTEL:
1982 case SPIRV::OpAsmINTEL:
1983 case SPIRV::OpAsmCallINTEL:
1984 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_inline_assembly)) {
1985 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_inline_assembly);
1986 Reqs.addCapability(SPIRV::Capability::AsmINTEL);
1987 }
1988 break;
1989 case SPIRV::OpTypeCooperativeMatrixKHR: {
1990 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix))
1992 "OpTypeCooperativeMatrixKHR type requires the "
1993 "following SPIR-V extension: SPV_KHR_cooperative_matrix",
1994 false);
1995 Reqs.addExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix);
1996 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixKHR);
1997 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1998 SPIRVTypeInst TypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
1999 if (isBFloat16Type(TypeDef))
2000 Reqs.addCapability(SPIRV::Capability::BFloat16CooperativeMatrixKHR);
2001 break;
2002 }
2003 case SPIRV::OpArithmeticFenceEXT:
2004 if (!ST.canUseExtension(SPIRV::Extension::SPV_EXT_arithmetic_fence))
2005 report_fatal_error("OpArithmeticFenceEXT requires the "
2006 "following SPIR-V extension: SPV_EXT_arithmetic_fence",
2007 false);
2008 Reqs.addExtension(SPIRV::Extension::SPV_EXT_arithmetic_fence);
2009 Reqs.addCapability(SPIRV::Capability::ArithmeticFenceEXT);
2010 break;
2011 case SPIRV::OpControlBarrierArriveINTEL:
2012 case SPIRV::OpControlBarrierWaitINTEL:
2013 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_split_barrier)) {
2014 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_split_barrier);
2015 Reqs.addCapability(SPIRV::Capability::SplitBarrierINTEL);
2016 }
2017 break;
2018 case SPIRV::OpCooperativeMatrixMulAddKHR: {
2019 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix))
2020 report_fatal_error("Cooperative matrix instructions require the "
2021 "following SPIR-V extension: "
2022 "SPV_KHR_cooperative_matrix",
2023 false);
2024 Reqs.addExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix);
2025 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixKHR);
2026 constexpr unsigned MulAddMaxSize = 6;
2027 if (MI.getNumOperands() != MulAddMaxSize)
2028 break;
2029 const int64_t CoopOperands = MI.getOperand(MulAddMaxSize - 1).getImm();
2030 if (CoopOperands &
2031 SPIRV::CooperativeMatrixOperands::MatrixAAndBTF32ComponentsINTEL) {
2032 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2033 report_fatal_error("MatrixAAndBTF32ComponentsINTEL type interpretation "
2034 "require the following SPIR-V extension: "
2035 "SPV_INTEL_joint_matrix",
2036 false);
2037 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2038 Reqs.addCapability(
2039 SPIRV::Capability::CooperativeMatrixTF32ComponentTypeINTEL);
2040 }
2041 if (CoopOperands & SPIRV::CooperativeMatrixOperands::
2042 MatrixAAndBBFloat16ComponentsINTEL ||
2043 CoopOperands &
2044 SPIRV::CooperativeMatrixOperands::MatrixCBFloat16ComponentsINTEL ||
2045 CoopOperands & SPIRV::CooperativeMatrixOperands::
2046 MatrixResultBFloat16ComponentsINTEL) {
2047 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2048 report_fatal_error("***BF16ComponentsINTEL type interpretations "
2049 "require the following SPIR-V extension: "
2050 "SPV_INTEL_joint_matrix",
2051 false);
2052 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2053 Reqs.addCapability(
2054 SPIRV::Capability::CooperativeMatrixBFloat16ComponentTypeINTEL);
2055 }
2056 break;
2057 }
2058 case SPIRV::OpCooperativeMatrixLoadKHR:
2059 case SPIRV::OpCooperativeMatrixStoreKHR:
2060 case SPIRV::OpCooperativeMatrixLoadCheckedINTEL:
2061 case SPIRV::OpCooperativeMatrixStoreCheckedINTEL:
2062 case SPIRV::OpCooperativeMatrixPrefetchINTEL: {
2063 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix))
2064 report_fatal_error("Cooperative matrix instructions require the "
2065 "following SPIR-V extension: "
2066 "SPV_KHR_cooperative_matrix",
2067 false);
2068 Reqs.addExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix);
2069 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixKHR);
2070
2071 // Check Layout operand in case if it's not a standard one and add the
2072 // appropriate capability.
2073 std::unordered_map<unsigned, unsigned> LayoutToInstMap = {
2074 {SPIRV::OpCooperativeMatrixLoadKHR, 3},
2075 {SPIRV::OpCooperativeMatrixStoreKHR, 2},
2076 {SPIRV::OpCooperativeMatrixLoadCheckedINTEL, 5},
2077 {SPIRV::OpCooperativeMatrixStoreCheckedINTEL, 4},
2078 {SPIRV::OpCooperativeMatrixPrefetchINTEL, 4}};
2079
2080 const unsigned LayoutNum = LayoutToInstMap[Op];
2081 Register RegLayout = MI.getOperand(LayoutNum).getReg();
2082 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
2083 MachineInstr *MILayout = MRI.getUniqueVRegDef(RegLayout);
2084 if (MILayout->getOpcode() == SPIRV::OpConstantI) {
2085 const unsigned LayoutVal = MILayout->getOperand(2).getImm();
2086 if (LayoutVal ==
2087 static_cast<unsigned>(SPIRV::CooperativeMatrixLayout::PackedINTEL)) {
2088 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2089 report_fatal_error("PackedINTEL layout require the following SPIR-V "
2090 "extension: SPV_INTEL_joint_matrix",
2091 false);
2092 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2093 Reqs.addCapability(SPIRV::Capability::PackedCooperativeMatrixINTEL);
2094 }
2095 }
2096
2097 // Nothing to do.
2098 if (Op == SPIRV::OpCooperativeMatrixLoadKHR ||
2099 Op == SPIRV::OpCooperativeMatrixStoreKHR)
2100 break;
2101
2102 std::string InstName;
2103 switch (Op) {
2104 case SPIRV::OpCooperativeMatrixPrefetchINTEL:
2105 InstName = "OpCooperativeMatrixPrefetchINTEL";
2106 break;
2107 case SPIRV::OpCooperativeMatrixLoadCheckedINTEL:
2108 InstName = "OpCooperativeMatrixLoadCheckedINTEL";
2109 break;
2110 case SPIRV::OpCooperativeMatrixStoreCheckedINTEL:
2111 InstName = "OpCooperativeMatrixStoreCheckedINTEL";
2112 break;
2113 }
2114
2115 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix)) {
2116 const std::string ErrorMsg =
2117 InstName + " instruction requires the "
2118 "following SPIR-V extension: SPV_INTEL_joint_matrix";
2119 report_fatal_error(ErrorMsg.c_str(), false);
2120 }
2121 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2122 if (Op == SPIRV::OpCooperativeMatrixPrefetchINTEL) {
2123 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixPrefetchINTEL);
2124 break;
2125 }
2126 Reqs.addCapability(
2127 SPIRV::Capability::CooperativeMatrixCheckedInstructionsINTEL);
2128 break;
2129 }
2130 case SPIRV::OpCooperativeMatrixConstructCheckedINTEL:
2131 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2132 report_fatal_error("OpCooperativeMatrixConstructCheckedINTEL "
2133 "instructions require the following SPIR-V extension: "
2134 "SPV_INTEL_joint_matrix",
2135 false);
2136 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2137 Reqs.addCapability(
2138 SPIRV::Capability::CooperativeMatrixCheckedInstructionsINTEL);
2139 break;
2140 case SPIRV::OpReadPipeBlockingALTERA:
2141 case SPIRV::OpWritePipeBlockingALTERA:
2142 if (ST.canUseExtension(SPIRV::Extension::SPV_ALTERA_blocking_pipes)) {
2143 Reqs.addExtension(SPIRV::Extension::SPV_ALTERA_blocking_pipes);
2144 Reqs.addCapability(SPIRV::Capability::BlockingPipesALTERA);
2145 }
2146 break;
2147 case SPIRV::OpCooperativeMatrixGetElementCoordINTEL:
2148 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2149 report_fatal_error("OpCooperativeMatrixGetElementCoordINTEL requires the "
2150 "following SPIR-V extension: SPV_INTEL_joint_matrix",
2151 false);
2152 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2153 Reqs.addCapability(
2154 SPIRV::Capability::CooperativeMatrixInvocationInstructionsINTEL);
2155 break;
2156 case SPIRV::OpConvertHandleToImageINTEL:
2157 case SPIRV::OpConvertHandleToSamplerINTEL:
2158 case SPIRV::OpConvertHandleToSampledImageINTEL: {
2159 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bindless_images))
2160 report_fatal_error("OpConvertHandleTo[Image/Sampler/SampledImage]INTEL "
2161 "instructions require the following SPIR-V extension: "
2162 "SPV_INTEL_bindless_images",
2163 false);
2164 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
2165 SPIRV::AddressingModel::AddressingModel AddrModel = MAI.Addr;
2166 SPIRVTypeInst TyDef = GR->getSPIRVTypeForVReg(MI.getOperand(1).getReg());
2167 if (Op == SPIRV::OpConvertHandleToImageINTEL &&
2168 TyDef->getOpcode() != SPIRV::OpTypeImage) {
2169 report_fatal_error("Incorrect return type for the instruction "
2170 "OpConvertHandleToImageINTEL",
2171 false);
2172 } else if (Op == SPIRV::OpConvertHandleToSamplerINTEL &&
2173 TyDef->getOpcode() != SPIRV::OpTypeSampler) {
2174 report_fatal_error("Incorrect return type for the instruction "
2175 "OpConvertHandleToSamplerINTEL",
2176 false);
2177 } else if (Op == SPIRV::OpConvertHandleToSampledImageINTEL &&
2178 TyDef->getOpcode() != SPIRV::OpTypeSampledImage) {
2179 report_fatal_error("Incorrect return type for the instruction "
2180 "OpConvertHandleToSampledImageINTEL",
2181 false);
2182 }
2183 SPIRVTypeInst SpvTy = GR->getSPIRVTypeForVReg(MI.getOperand(2).getReg());
2184 unsigned Bitwidth = GR->getScalarOrVectorBitWidth(SpvTy);
2185 if (!(Bitwidth == 32 && AddrModel == SPIRV::AddressingModel::Physical32) &&
2186 !(Bitwidth == 64 && AddrModel == SPIRV::AddressingModel::Physical64)) {
2188 "Parameter value must be a 32-bit scalar in case of "
2189 "Physical32 addressing model or a 64-bit scalar in case of "
2190 "Physical64 addressing model",
2191 false);
2192 }
2193 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bindless_images);
2194 Reqs.addCapability(SPIRV::Capability::BindlessImagesINTEL);
2195 break;
2196 }
2197 case SPIRV::OpSubgroup2DBlockLoadINTEL:
2198 case SPIRV::OpSubgroup2DBlockLoadTransposeINTEL:
2199 case SPIRV::OpSubgroup2DBlockLoadTransformINTEL:
2200 case SPIRV::OpSubgroup2DBlockPrefetchINTEL:
2201 case SPIRV::OpSubgroup2DBlockStoreINTEL: {
2202 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_2d_block_io))
2203 report_fatal_error("OpSubgroup2DBlock[Load/LoadTranspose/LoadTransform/"
2204 "Prefetch/Store]INTEL instructions require the "
2205 "following SPIR-V extension: SPV_INTEL_2d_block_io",
2206 false);
2207 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_2d_block_io);
2208 Reqs.addCapability(SPIRV::Capability::Subgroup2DBlockIOINTEL);
2209
2210 if (Op == SPIRV::OpSubgroup2DBlockLoadTransposeINTEL) {
2211 Reqs.addCapability(SPIRV::Capability::Subgroup2DBlockTransposeINTEL);
2212 break;
2213 }
2214 if (Op == SPIRV::OpSubgroup2DBlockLoadTransformINTEL) {
2215 Reqs.addCapability(SPIRV::Capability::Subgroup2DBlockTransformINTEL);
2216 break;
2217 }
2218 break;
2219 }
2220 case SPIRV::OpKill: {
2221 Reqs.addCapability(SPIRV::Capability::Shader);
2222 } break;
2223 case SPIRV::OpDemoteToHelperInvocation:
2224 Reqs.addCapability(SPIRV::Capability::DemoteToHelperInvocation);
2225
2226 if (ST.canUseExtension(
2227 SPIRV::Extension::SPV_EXT_demote_to_helper_invocation)) {
2228 if (!ST.isAtLeastSPIRVVer(llvm::VersionTuple(1, 6)))
2229 Reqs.addExtension(
2230 SPIRV::Extension::SPV_EXT_demote_to_helper_invocation);
2231 }
2232 break;
2233 case SPIRV::OpSDot:
2234 case SPIRV::OpUDot:
2235 case SPIRV::OpSUDot:
2236 case SPIRV::OpSDotAccSat:
2237 case SPIRV::OpUDotAccSat:
2238 case SPIRV::OpSUDotAccSat:
2239 AddDotProductRequirements(MI, Reqs, ST);
2240 break;
2241 case SPIRV::OpImageSampleImplicitLod:
2242 Reqs.addCapability(SPIRV::Capability::Shader);
2243 addImageOperandReqs(MI, Reqs, ST, 4);
2244 break;
2245 case SPIRV::OpImageSampleExplicitLod:
2246 addImageOperandReqs(MI, Reqs, ST, 4);
2247 break;
2248 case SPIRV::OpImageSampleDrefImplicitLod:
2249 Reqs.addCapability(SPIRV::Capability::Shader);
2250 addImageOperandReqs(MI, Reqs, ST, 5);
2251 break;
2252 case SPIRV::OpImageSampleDrefExplicitLod:
2253 Reqs.addCapability(SPIRV::Capability::Shader);
2254 addImageOperandReqs(MI, Reqs, ST, 5);
2255 break;
2256 case SPIRV::OpImageFetch:
2257 Reqs.addCapability(SPIRV::Capability::Shader);
2258 addImageOperandReqs(MI, Reqs, ST, 4);
2259 break;
2260 case SPIRV::OpImageDrefGather:
2261 case SPIRV::OpImageGather:
2262 Reqs.addCapability(SPIRV::Capability::Shader);
2263 addImageOperandReqs(MI, Reqs, ST, 5);
2264 break;
2265 case SPIRV::OpImageRead: {
2266 Register ImageReg = MI.getOperand(2).getReg();
2267 SPIRVTypeInst TypeDef = ST.getSPIRVGlobalRegistry()->getResultType(
2268 ImageReg, const_cast<MachineFunction *>(MI.getMF()));
2269 // OpImageRead and OpImageWrite can use Unknown Image Formats
2270 // when the Kernel capability is declared. In the OpenCL environment we are
2271 // not allowed to produce
2272 // StorageImageReadWithoutFormat/StorageImageWriteWithoutFormat, see
2273 // https://github.com/KhronosGroup/SPIRV-Headers/issues/487
2274
2275 if (isImageTypeWithUnknownFormat(TypeDef) && ST.isShader())
2276 Reqs.addCapability(SPIRV::Capability::StorageImageReadWithoutFormat);
2277 break;
2278 }
2279 case SPIRV::OpImageWrite: {
2280 Register ImageReg = MI.getOperand(0).getReg();
2281 SPIRVTypeInst TypeDef = ST.getSPIRVGlobalRegistry()->getResultType(
2282 ImageReg, const_cast<MachineFunction *>(MI.getMF()));
2283 // OpImageRead and OpImageWrite can use Unknown Image Formats
2284 // when the Kernel capability is declared. In the OpenCL environment we are
2285 // not allowed to produce
2286 // StorageImageReadWithoutFormat/StorageImageWriteWithoutFormat, see
2287 // https://github.com/KhronosGroup/SPIRV-Headers/issues/487
2288
2289 if (isImageTypeWithUnknownFormat(TypeDef) && ST.isShader())
2290 Reqs.addCapability(SPIRV::Capability::StorageImageWriteWithoutFormat);
2291 break;
2292 }
2293 case SPIRV::OpTypeStructContinuedINTEL:
2294 case SPIRV::OpConstantCompositeContinuedINTEL:
2295 case SPIRV::OpSpecConstantCompositeContinuedINTEL:
2296 case SPIRV::OpCompositeConstructContinuedINTEL: {
2297 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_long_composites))
2299 "Continued instructions require the "
2300 "following SPIR-V extension: SPV_INTEL_long_composites",
2301 false);
2302 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_long_composites);
2303 Reqs.addCapability(SPIRV::Capability::LongCompositesINTEL);
2304 break;
2305 }
2306 case SPIRV::OpArbitraryFloatEQALTERA:
2307 case SPIRV::OpArbitraryFloatGEALTERA:
2308 case SPIRV::OpArbitraryFloatGTALTERA:
2309 case SPIRV::OpArbitraryFloatLEALTERA:
2310 case SPIRV::OpArbitraryFloatLTALTERA:
2311 case SPIRV::OpArbitraryFloatCbrtALTERA:
2312 case SPIRV::OpArbitraryFloatCosALTERA:
2313 case SPIRV::OpArbitraryFloatCosPiALTERA:
2314 case SPIRV::OpArbitraryFloatExp10ALTERA:
2315 case SPIRV::OpArbitraryFloatExp2ALTERA:
2316 case SPIRV::OpArbitraryFloatExpALTERA:
2317 case SPIRV::OpArbitraryFloatExpm1ALTERA:
2318 case SPIRV::OpArbitraryFloatHypotALTERA:
2319 case SPIRV::OpArbitraryFloatLog10ALTERA:
2320 case SPIRV::OpArbitraryFloatLog1pALTERA:
2321 case SPIRV::OpArbitraryFloatLog2ALTERA:
2322 case SPIRV::OpArbitraryFloatLogALTERA:
2323 case SPIRV::OpArbitraryFloatRecipALTERA:
2324 case SPIRV::OpArbitraryFloatSinCosALTERA:
2325 case SPIRV::OpArbitraryFloatSinCosPiALTERA:
2326 case SPIRV::OpArbitraryFloatSinALTERA:
2327 case SPIRV::OpArbitraryFloatSinPiALTERA:
2328 case SPIRV::OpArbitraryFloatSqrtALTERA:
2329 case SPIRV::OpArbitraryFloatACosALTERA:
2330 case SPIRV::OpArbitraryFloatACosPiALTERA:
2331 case SPIRV::OpArbitraryFloatAddALTERA:
2332 case SPIRV::OpArbitraryFloatASinALTERA:
2333 case SPIRV::OpArbitraryFloatASinPiALTERA:
2334 case SPIRV::OpArbitraryFloatATan2ALTERA:
2335 case SPIRV::OpArbitraryFloatATanALTERA:
2336 case SPIRV::OpArbitraryFloatATanPiALTERA:
2337 case SPIRV::OpArbitraryFloatCastFromIntALTERA:
2338 case SPIRV::OpArbitraryFloatCastALTERA:
2339 case SPIRV::OpArbitraryFloatCastToIntALTERA:
2340 case SPIRV::OpArbitraryFloatDivALTERA:
2341 case SPIRV::OpArbitraryFloatMulALTERA:
2342 case SPIRV::OpArbitraryFloatPowALTERA:
2343 case SPIRV::OpArbitraryFloatPowNALTERA:
2344 case SPIRV::OpArbitraryFloatPowRALTERA:
2345 case SPIRV::OpArbitraryFloatRSqrtALTERA:
2346 case SPIRV::OpArbitraryFloatSubALTERA: {
2347 if (!ST.canUseExtension(
2348 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_floating_point))
2350 "Floating point instructions can't be translated correctly without "
2351 "enabled SPV_ALTERA_arbitrary_precision_floating_point extension!",
2352 false);
2353 Reqs.addExtension(
2354 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_floating_point);
2355 Reqs.addCapability(
2356 SPIRV::Capability::ArbitraryPrecisionFloatingPointALTERA);
2357 break;
2358 }
2359 case SPIRV::OpSubgroupMatrixMultiplyAccumulateINTEL: {
2360 if (!ST.canUseExtension(
2361 SPIRV::Extension::SPV_INTEL_subgroup_matrix_multiply_accumulate))
2363 "OpSubgroupMatrixMultiplyAccumulateINTEL instruction requires the "
2364 "following SPIR-V "
2365 "extension: SPV_INTEL_subgroup_matrix_multiply_accumulate",
2366 false);
2367 Reqs.addExtension(
2368 SPIRV::Extension::SPV_INTEL_subgroup_matrix_multiply_accumulate);
2369 Reqs.addCapability(
2370 SPIRV::Capability::SubgroupMatrixMultiplyAccumulateINTEL);
2371 break;
2372 }
2373 case SPIRV::OpBitwiseFunctionINTEL: {
2374 if (!ST.canUseExtension(
2375 SPIRV::Extension::SPV_INTEL_ternary_bitwise_function))
2377 "OpBitwiseFunctionINTEL instruction requires the following SPIR-V "
2378 "extension: SPV_INTEL_ternary_bitwise_function",
2379 false);
2380 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_ternary_bitwise_function);
2381 Reqs.addCapability(SPIRV::Capability::TernaryBitwiseFunctionINTEL);
2382 break;
2383 }
2384 case SPIRV::OpCopyMemorySized: {
2385 Reqs.addCapability(SPIRV::Capability::Addresses);
2386 // TODO: Add UntypedPointersKHR when implemented.
2387 break;
2388 }
2389 case SPIRV::OpPredicatedLoadINTEL:
2390 case SPIRV::OpPredicatedStoreINTEL: {
2391 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_predicated_io))
2393 "OpPredicated[Load/Store]INTEL instructions require "
2394 "the following SPIR-V extension: SPV_INTEL_predicated_io",
2395 false);
2396 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_predicated_io);
2397 Reqs.addCapability(SPIRV::Capability::PredicatedIOINTEL);
2398 break;
2399 }
2400 case SPIRV::OpFAddS:
2401 case SPIRV::OpFSubS:
2402 case SPIRV::OpFMulS:
2403 case SPIRV::OpFDivS:
2404 case SPIRV::OpFRemS:
2405 case SPIRV::OpFMod:
2406 case SPIRV::OpFNegate:
2407 case SPIRV::OpFAddV:
2408 case SPIRV::OpFSubV:
2409 case SPIRV::OpFMulV:
2410 case SPIRV::OpFDivV:
2411 case SPIRV::OpFRemV:
2412 case SPIRV::OpFNegateV: {
2413 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
2414 SPIRVTypeInst TypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
2415 if (TypeDef->getOpcode() == SPIRV::OpTypeVector)
2416 TypeDef = MRI.getVRegDef(TypeDef->getOperand(1).getReg());
2417 if (isBFloat16Type(TypeDef)) {
2418 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic))
2420 "Arithmetic instructions with bfloat16 arguments require the "
2421 "following SPIR-V extension: SPV_INTEL_bfloat16_arithmetic",
2422 false);
2423 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic);
2424 Reqs.addCapability(SPIRV::Capability::BFloat16ArithmeticINTEL);
2425 }
2426 break;
2427 }
2428 case SPIRV::OpOrdered:
2429 case SPIRV::OpUnordered:
2430 case SPIRV::OpFOrdEqual:
2431 case SPIRV::OpFOrdNotEqual:
2432 case SPIRV::OpFOrdLessThan:
2433 case SPIRV::OpFOrdLessThanEqual:
2434 case SPIRV::OpFOrdGreaterThan:
2435 case SPIRV::OpFOrdGreaterThanEqual:
2436 case SPIRV::OpFUnordEqual:
2437 case SPIRV::OpFUnordNotEqual:
2438 case SPIRV::OpFUnordLessThan:
2439 case SPIRV::OpFUnordLessThanEqual:
2440 case SPIRV::OpFUnordGreaterThan:
2441 case SPIRV::OpFUnordGreaterThanEqual: {
2442 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
2443 MachineInstr *OperandDef = MRI.getVRegDef(MI.getOperand(2).getReg());
2444 SPIRVTypeInst TypeDef = MRI.getVRegDef(OperandDef->getOperand(1).getReg());
2445 if (TypeDef->getOpcode() == SPIRV::OpTypeVector)
2446 TypeDef = MRI.getVRegDef(TypeDef->getOperand(1).getReg());
2447 if (isBFloat16Type(TypeDef)) {
2448 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic))
2450 "Relational instructions with bfloat16 arguments require the "
2451 "following SPIR-V extension: SPV_INTEL_bfloat16_arithmetic",
2452 false);
2453 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic);
2454 Reqs.addCapability(SPIRV::Capability::BFloat16ArithmeticINTEL);
2455 }
2456 break;
2457 }
2458 case SPIRV::OpDPdxCoarse:
2459 case SPIRV::OpDPdyCoarse:
2460 case SPIRV::OpDPdxFine:
2461 case SPIRV::OpDPdyFine: {
2462 Reqs.addCapability(SPIRV::Capability::DerivativeControl);
2463 break;
2464 }
2465 case SPIRV::OpLoopControlINTEL: {
2466 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_unstructured_loop_controls);
2467 Reqs.addCapability(SPIRV::Capability::UnstructuredLoopControlsINTEL);
2468 break;
2469 }
2470
2471 default:
2472 break;
2473 }
2474
2475 // If we require capability Shader, then we can remove the requirement for
2476 // the BitInstructions capability, since Shader is a superset capability
2477 // of BitInstructions.
2478 Reqs.removeCapabilityIf(SPIRV::Capability::BitInstructions,
2479 SPIRV::Capability::Shader);
2480}
2481
2482static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI,
2483 MachineModuleInfo *MMI, const SPIRVSubtarget &ST) {
2484 // Collect requirements for existing instructions.
2485 for (const Function &F : M) {
2487 if (!MF)
2488 continue;
2489 for (const MachineBasicBlock &MBB : *MF)
2490 for (const MachineInstr &MI : MBB)
2491 addInstrRequirements(MI, MAI, ST);
2492 }
2493 // Collect requirements for OpExecutionMode instructions.
2494 auto Node = M.getNamedMetadata("spirv.ExecutionMode");
2495 if (Node) {
2496 bool RequireFloatControls = false, RequireIntelFloatControls2 = false,
2497 RequireKHRFloatControls2 = false,
2498 VerLower14 = !ST.isAtLeastSPIRVVer(VersionTuple(1, 4));
2499 bool HasIntelFloatControls2 =
2500 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_float_controls2);
2501 bool HasKHRFloatControls2 =
2502 ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2);
2503 for (unsigned i = 0; i < Node->getNumOperands(); i++) {
2504 MDNode *MDN = cast<MDNode>(Node->getOperand(i));
2505 const MDOperand &MDOp = MDN->getOperand(1);
2506 if (auto *CMeta = dyn_cast<ConstantAsMetadata>(MDOp)) {
2507 Constant *C = CMeta->getValue();
2508 if (ConstantInt *Const = dyn_cast<ConstantInt>(C)) {
2509 auto EM = Const->getZExtValue();
2510 // SPV_KHR_float_controls is not available until v1.4:
2511 // add SPV_KHR_float_controls if the version is too low
2512 switch (EM) {
2513 case SPIRV::ExecutionMode::DenormPreserve:
2514 case SPIRV::ExecutionMode::DenormFlushToZero:
2515 case SPIRV::ExecutionMode::RoundingModeRTE:
2516 case SPIRV::ExecutionMode::RoundingModeRTZ:
2517 RequireFloatControls = VerLower14;
2519 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2520 break;
2521 case SPIRV::ExecutionMode::RoundingModeRTPINTEL:
2522 case SPIRV::ExecutionMode::RoundingModeRTNINTEL:
2523 case SPIRV::ExecutionMode::FloatingPointModeALTINTEL:
2524 case SPIRV::ExecutionMode::FloatingPointModeIEEEINTEL:
2525 if (HasIntelFloatControls2) {
2526 RequireIntelFloatControls2 = true;
2528 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2529 }
2530 break;
2531 case SPIRV::ExecutionMode::FPFastMathDefault: {
2532 if (HasKHRFloatControls2) {
2533 RequireKHRFloatControls2 = true;
2535 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2536 }
2537 break;
2538 }
2539 case SPIRV::ExecutionMode::ContractionOff:
2540 case SPIRV::ExecutionMode::SignedZeroInfNanPreserve:
2541 if (HasKHRFloatControls2) {
2542 RequireKHRFloatControls2 = true;
2544 SPIRV::OperandCategory::ExecutionModeOperand,
2545 SPIRV::ExecutionMode::FPFastMathDefault, ST);
2546 } else {
2548 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2549 }
2550 break;
2551 default:
2553 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2554 }
2555 }
2556 }
2557 }
2558 if (RequireFloatControls &&
2559 ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls))
2560 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls);
2561 if (RequireIntelFloatControls2)
2562 MAI.Reqs.addExtension(SPIRV::Extension::SPV_INTEL_float_controls2);
2563 if (RequireKHRFloatControls2)
2564 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls2);
2565 }
2566 for (const Function &F : M) {
2567 if (F.isDeclaration())
2568 continue;
2569 if (F.getMetadata("reqd_work_group_size"))
2571 SPIRV::OperandCategory::ExecutionModeOperand,
2572 SPIRV::ExecutionMode::LocalSize, ST);
2573 if (F.getFnAttribute("hlsl.numthreads").isValid()) {
2575 SPIRV::OperandCategory::ExecutionModeOperand,
2576 SPIRV::ExecutionMode::LocalSize, ST);
2577 }
2578 if (F.getFnAttribute("enable-maximal-reconvergence").getValueAsBool()) {
2579 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_maximal_reconvergence);
2580 }
2581 if (F.getMetadata("work_group_size_hint"))
2583 SPIRV::OperandCategory::ExecutionModeOperand,
2584 SPIRV::ExecutionMode::LocalSizeHint, ST);
2585 if (F.getMetadata("intel_reqd_sub_group_size"))
2587 SPIRV::OperandCategory::ExecutionModeOperand,
2588 SPIRV::ExecutionMode::SubgroupSize, ST);
2589 if (F.getMetadata("max_work_group_size"))
2591 SPIRV::OperandCategory::ExecutionModeOperand,
2592 SPIRV::ExecutionMode::MaxWorkgroupSizeINTEL, ST);
2593 if (F.getMetadata("vec_type_hint"))
2595 SPIRV::OperandCategory::ExecutionModeOperand,
2596 SPIRV::ExecutionMode::VecTypeHint, ST);
2597
2598 if (F.hasOptNone()) {
2599 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_optnone)) {
2600 MAI.Reqs.addExtension(SPIRV::Extension::SPV_INTEL_optnone);
2601 MAI.Reqs.addCapability(SPIRV::Capability::OptNoneINTEL);
2602 } else if (ST.canUseExtension(SPIRV::Extension::SPV_EXT_optnone)) {
2603 MAI.Reqs.addExtension(SPIRV::Extension::SPV_EXT_optnone);
2604 MAI.Reqs.addCapability(SPIRV::Capability::OptNoneEXT);
2605 }
2606 }
2607 }
2608}
2609
2610static unsigned getFastMathFlags(const MachineInstr &I,
2611 const SPIRVSubtarget &ST) {
2612 unsigned Flags = SPIRV::FPFastMathMode::None;
2613 bool CanUseKHRFloatControls2 =
2614 ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2);
2615 if (I.getFlag(MachineInstr::MIFlag::FmNoNans))
2616 Flags |= SPIRV::FPFastMathMode::NotNaN;
2617 if (I.getFlag(MachineInstr::MIFlag::FmNoInfs))
2618 Flags |= SPIRV::FPFastMathMode::NotInf;
2619 if (I.getFlag(MachineInstr::MIFlag::FmNsz))
2620 Flags |= SPIRV::FPFastMathMode::NSZ;
2621 if (I.getFlag(MachineInstr::MIFlag::FmArcp))
2622 Flags |= SPIRV::FPFastMathMode::AllowRecip;
2623 if (I.getFlag(MachineInstr::MIFlag::FmContract) && CanUseKHRFloatControls2)
2624 Flags |= SPIRV::FPFastMathMode::AllowContract;
2625 if (I.getFlag(MachineInstr::MIFlag::FmReassoc)) {
2626 if (CanUseKHRFloatControls2)
2627 // LLVM reassoc maps to SPIRV transform, see
2628 // https://github.com/KhronosGroup/SPIRV-Registry/issues/326 for details.
2629 // Because we are enabling AllowTransform, we must enable AllowReassoc and
2630 // AllowContract too, as required by SPIRV spec. Also, we used to map
2631 // MIFlag::FmReassoc to FPFastMathMode::Fast, which now should instead by
2632 // replaced by turning all the other bits instead. Therefore, we're
2633 // enabling every bit here except None and Fast.
2634 Flags |= SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
2635 SPIRV::FPFastMathMode::NSZ | SPIRV::FPFastMathMode::AllowRecip |
2636 SPIRV::FPFastMathMode::AllowTransform |
2637 SPIRV::FPFastMathMode::AllowReassoc |
2638 SPIRV::FPFastMathMode::AllowContract;
2639 else
2640 Flags |= SPIRV::FPFastMathMode::Fast;
2641 }
2642
2643 if (CanUseKHRFloatControls2) {
2644 // Error out if SPIRV::FPFastMathMode::Fast is enabled.
2645 assert(!(Flags & SPIRV::FPFastMathMode::Fast) &&
2646 "SPIRV::FPFastMathMode::Fast is deprecated and should not be used "
2647 "anymore.");
2648
2649 // Error out if AllowTransform is enabled without AllowReassoc and
2650 // AllowContract.
2651 assert((!(Flags & SPIRV::FPFastMathMode::AllowTransform) ||
2652 ((Flags & SPIRV::FPFastMathMode::AllowReassoc &&
2653 Flags & SPIRV::FPFastMathMode::AllowContract))) &&
2654 "SPIRV::FPFastMathMode::AllowTransform requires AllowReassoc and "
2655 "AllowContract flags to be enabled as well.");
2656 }
2657
2658 return Flags;
2659}
2660
2661static bool isFastMathModeAvailable(const SPIRVSubtarget &ST) {
2662 if (ST.isKernel())
2663 return true;
2664 if (ST.getSPIRVVersion() < VersionTuple(1, 2))
2665 return false;
2666 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2);
2667}
2668
2669static void handleMIFlagDecoration(
2670 MachineInstr &I, const SPIRVSubtarget &ST, const SPIRVInstrInfo &TII,
2672 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec) {
2673 if (I.getFlag(MachineInstr::MIFlag::NoSWrap) && TII.canUseNSW(I) &&
2674 getSymbolicOperandRequirements(SPIRV::OperandCategory::DecorationOperand,
2675 SPIRV::Decoration::NoSignedWrap, ST, Reqs)
2676 .IsSatisfiable) {
2677 buildOpDecorate(I.getOperand(0).getReg(), I, TII,
2678 SPIRV::Decoration::NoSignedWrap, {});
2679 }
2680 if (I.getFlag(MachineInstr::MIFlag::NoUWrap) && TII.canUseNUW(I) &&
2681 getSymbolicOperandRequirements(SPIRV::OperandCategory::DecorationOperand,
2682 SPIRV::Decoration::NoUnsignedWrap, ST,
2683 Reqs)
2684 .IsSatisfiable) {
2685 buildOpDecorate(I.getOperand(0).getReg(), I, TII,
2686 SPIRV::Decoration::NoUnsignedWrap, {});
2687 }
2688 // In Kernel environments, FPFastMathMode on OpExtInst is valid per core
2689 // spec. For other instruction types, SPV_KHR_float_controls2 is required.
2690 bool CanUseFM =
2691 TII.canUseFastMathFlags(
2692 I, ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2)) ||
2693 (ST.isKernel() && I.getOpcode() == SPIRV::OpExtInst);
2694 if (!CanUseFM)
2695 return;
2696
2697 unsigned FMFlags = getFastMathFlags(I, ST);
2698 if (FMFlags == SPIRV::FPFastMathMode::None) {
2699 // We also need to check if any FPFastMathDefault info was set for the
2700 // types used in this instruction.
2701 if (FPFastMathDefaultInfoVec.empty())
2702 return;
2703
2704 // There are three types of instructions that can use fast math flags:
2705 // 1. Arithmetic instructions (FAdd, FMul, FSub, FDiv, FRem, etc.)
2706 // 2. Relational instructions (FCmp, FOrd, FUnord, etc.)
2707 // 3. Extended instructions (ExtInst)
2708 // For arithmetic instructions, the floating point type can be in the
2709 // result type or in the operands, but they all must be the same.
2710 // For the relational and logical instructions, the floating point type
2711 // can only be in the operands 1 and 2, not the result type. Also, the
2712 // operands must have the same type. For the extended instructions, the
2713 // floating point type can be in the result type or in the operands. It's
2714 // unclear if the operands and the result type must be the same. Let's
2715 // assume they must be. Therefore, for 1. and 2., we can check the first
2716 // operand type, and for 3. we can check the result type.
2717 assert(I.getNumOperands() >= 3 && "Expected at least 3 operands");
2718 Register ResReg = I.getOpcode() == SPIRV::OpExtInst
2719 ? I.getOperand(1).getReg()
2720 : I.getOperand(2).getReg();
2721 SPIRVTypeInst ResType = GR->getSPIRVTypeForVReg(ResReg, I.getMF());
2722 const Type *Ty = GR->getTypeForSPIRVType(ResType);
2723 Ty = Ty->isVectorTy() ? cast<VectorType>(Ty)->getElementType() : Ty;
2724
2725 // Match instruction type with the FPFastMathDefaultInfoVec.
2726 bool Emit = false;
2727 for (SPIRV::FPFastMathDefaultInfo &Elem : FPFastMathDefaultInfoVec) {
2728 if (Ty == Elem.Ty) {
2729 FMFlags = Elem.FastMathFlags;
2730 Emit = Elem.ContractionOff || Elem.SignedZeroInfNanPreserve ||
2731 Elem.FPFastMathDefault;
2732 break;
2733 }
2734 }
2735
2736 if (FMFlags == SPIRV::FPFastMathMode::None && !Emit)
2737 return;
2738 }
2739 if (isFastMathModeAvailable(ST)) {
2740 Register DstReg = I.getOperand(0).getReg();
2741 buildOpDecorate(DstReg, I, TII, SPIRV::Decoration::FPFastMathMode,
2742 {FMFlags});
2743 }
2744}
2745
2746// Walk all functions and add decorations related to MI flags.
2747static void addDecorations(const Module &M, const SPIRVInstrInfo &TII,
2748 MachineModuleInfo *MMI, const SPIRVSubtarget &ST,
2750 const SPIRVGlobalRegistry *GR) {
2751 for (const Function &F : M) {
2753 if (!MF)
2754 continue;
2755
2756 for (auto &MBB : *MF)
2757 for (auto &MI : MBB)
2758 handleMIFlagDecoration(MI, ST, TII, MAI.Reqs, GR,
2760 }
2761}
2762
2763static void addMBBNames(const Module &M, const SPIRVInstrInfo &TII,
2764 MachineModuleInfo *MMI, const SPIRVSubtarget &ST,
2766 for (const Function &F : M) {
2768 if (!MF)
2769 continue;
2770 if (MF->getFunction()
2772 .isValid())
2773 continue;
2774 MachineRegisterInfo &MRI = MF->getRegInfo();
2775 for (auto &MBB : *MF) {
2776 if (!MBB.hasName() || MBB.empty())
2777 continue;
2778 // Emit basic block names.
2780 MRI.setRegClass(Reg, &SPIRV::IDRegClass);
2781 buildOpName(Reg, MBB.getName(), *std::prev(MBB.end()), TII);
2782 MCRegister GlobalReg = MAI.getOrCreateMBBRegister(MBB);
2783 MAI.setRegisterAlias(MF, Reg, GlobalReg);
2784 }
2785 }
2786}
2787
2788// patching Instruction::PHI to SPIRV::OpPhi
2789static void patchPhis(const Module &M, SPIRVGlobalRegistry *GR,
2790 const SPIRVInstrInfo &TII, MachineModuleInfo *MMI) {
2791 for (const Function &F : M) {
2793 if (!MF)
2794 continue;
2795 for (auto &MBB : *MF) {
2796 for (MachineInstr &MI : MBB.phis()) {
2797 MI.setDesc(TII.get(SPIRV::OpPhi));
2798 Register ResTypeReg = GR->getSPIRVTypeID(
2799 GR->getSPIRVTypeForVReg(MI.getOperand(0).getReg(), MF));
2800 MI.insert(MI.operands_begin() + 1,
2801 {MachineOperand::CreateReg(ResTypeReg, false)});
2802 }
2803 }
2804
2805 MF->getProperties().setNoPHIs();
2806 }
2807}
2808
2810 const Module &M, SPIRV::ModuleAnalysisInfo &MAI, const Function *F) {
2811 auto it = MAI.FPFastMathDefaultInfoMap.find(F);
2812 if (it != MAI.FPFastMathDefaultInfoMap.end())
2813 return it->second;
2814
2815 // If the map does not contain the entry, create a new one. Initialize it to
2816 // contain all 3 elements sorted by bit width of target type: {half, float,
2817 // double}.
2818 SPIRV::FPFastMathDefaultInfoVector FPFastMathDefaultInfoVec;
2819 FPFastMathDefaultInfoVec.emplace_back(Type::getHalfTy(M.getContext()),
2820 SPIRV::FPFastMathMode::None);
2821 FPFastMathDefaultInfoVec.emplace_back(Type::getFloatTy(M.getContext()),
2822 SPIRV::FPFastMathMode::None);
2823 FPFastMathDefaultInfoVec.emplace_back(Type::getDoubleTy(M.getContext()),
2824 SPIRV::FPFastMathMode::None);
2825 return MAI.FPFastMathDefaultInfoMap[F] = std::move(FPFastMathDefaultInfoVec);
2826}
2827
2829 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec,
2830 const Type *Ty) {
2831 size_t BitWidth = Ty->getScalarSizeInBits();
2832 int Index =
2834 BitWidth);
2835 assert(Index >= 0 && Index < 3 &&
2836 "Expected FPFastMathDefaultInfo for half, float, or double");
2837 assert(FPFastMathDefaultInfoVec.size() == 3 &&
2838 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
2839 return FPFastMathDefaultInfoVec[Index];
2840}
2841
2842static void collectFPFastMathDefaults(const Module &M,
2844 const SPIRVSubtarget &ST) {
2845 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
2846 return;
2847
2848 // Store the FPFastMathDefaultInfo in the FPFastMathDefaultInfoMap.
2849 // We need the entry point (function) as the key, and the target
2850 // type and flags as the value.
2851 // We also need to check ContractionOff and SignedZeroInfNanPreserve
2852 // execution modes, as they are now deprecated and must be replaced
2853 // with FPFastMathDefaultInfo.
2854 auto Node = M.getNamedMetadata("spirv.ExecutionMode");
2855 if (!Node)
2856 return;
2857
2858 for (unsigned i = 0; i < Node->getNumOperands(); i++) {
2859 MDNode *MDN = cast<MDNode>(Node->getOperand(i));
2860 assert(MDN->getNumOperands() >= 2 && "Expected at least 2 operands");
2861 const Function *F = cast<Function>(
2862 cast<ConstantAsMetadata>(MDN->getOperand(0))->getValue());
2863 const auto EM =
2865 cast<ConstantAsMetadata>(MDN->getOperand(1))->getValue())
2866 ->getZExtValue();
2867 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
2868 assert(MDN->getNumOperands() == 4 &&
2869 "Expected 4 operands for FPFastMathDefault");
2870
2871 const Type *T = cast<ValueAsMetadata>(MDN->getOperand(2))->getType();
2872 unsigned Flags =
2874 cast<ConstantAsMetadata>(MDN->getOperand(3))->getValue())
2875 ->getZExtValue();
2876 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2879 getFPFastMathDefaultInfo(FPFastMathDefaultInfoVec, T);
2880 Info.FastMathFlags = Flags;
2881 Info.FPFastMathDefault = true;
2882 } else if (EM == SPIRV::ExecutionMode::ContractionOff) {
2883 assert(MDN->getNumOperands() == 2 &&
2884 "Expected no operands for ContractionOff");
2885
2886 // We need to save this info for every possible FP type, i.e. {half,
2887 // float, double, fp128}.
2888 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2890 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
2891 Info.ContractionOff = true;
2892 }
2893 } else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
2894 assert(MDN->getNumOperands() == 3 &&
2895 "Expected 1 operand for SignedZeroInfNanPreserve");
2896 unsigned TargetWidth =
2898 cast<ConstantAsMetadata>(MDN->getOperand(2))->getValue())
2899 ->getZExtValue();
2900 // We need to save this info only for the FP type with TargetWidth.
2901 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2905 assert(Index >= 0 && Index < 3 &&
2906 "Expected FPFastMathDefaultInfo for half, float, or double");
2907 assert(FPFastMathDefaultInfoVec.size() == 3 &&
2908 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
2909 FPFastMathDefaultInfoVec[Index].SignedZeroInfNanPreserve = true;
2910 }
2911 }
2912}
2913
2915 AU.addRequired<TargetPassConfig>();
2916 AU.addRequired<MachineModuleInfoWrapperPass>();
2917}
2918
2920 SPIRVTargetMachine &TM =
2921 getAnalysis<TargetPassConfig>().getTM<SPIRVTargetMachine>();
2922 ST = TM.getSubtargetImpl();
2923 GR = ST->getSPIRVGlobalRegistry();
2924 TII = ST->getInstrInfo();
2925
2927
2928 setBaseInfo(M);
2929
2930 patchPhis(M, GR, *TII, MMI);
2931
2932 addMBBNames(M, *TII, MMI, *ST, MAI);
2933 collectFPFastMathDefaults(M, MAI, *ST);
2934 addDecorations(M, *TII, MMI, *ST, MAI, GR);
2935
2936 collectReqs(M, MAI, MMI, *ST);
2937
2938 // Process type/const/global var/func decl instructions, number their
2939 // destination registers from 0 to N, collect Extensions and Capabilities.
2940 collectReqs(M, MAI, MMI, *ST);
2941 collectDeclarations(M);
2942
2943 // Number rest of registers from N+1 onwards.
2944 numberRegistersGlobally(M);
2945
2946 // Collect OpName, OpEntryPoint, OpDecorate etc, process other instructions.
2947 processOtherInstrs(M);
2948
2949 // If there are no entry points, we need the Linkage capability.
2950 if (MAI.MS[SPIRV::MB_EntryPoints].empty())
2951 MAI.Reqs.addCapability(SPIRV::Capability::Linkage);
2952
2953 // Set maximum ID used.
2954 GR->setBound(MAI.MaxID);
2955
2956 return false;
2957}
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