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