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::Optional, cl::init(false));
40
42 AvoidCapabilities("avoid-spirv-capabilities",
43 cl::desc("SPIR-V capabilities to avoid if there are "
44 "other options enabling a feature"),
46 cl::values(clEnumValN(SPIRV::Capability::Shader, "Shader",
47 "SPIR-V Shader capability")));
48// Use sets instead of cl::list to check "if contains" condition
53
55
56INITIALIZE_PASS(SPIRVModuleAnalysis, DEBUG_TYPE, "SPIRV module analysis", true,
57 true)
58
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 // Became core in Vulkan 1.2
1056 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 5))) {
1058 {Capability::Int64Atomics, Capability::ShaderNonUniformEXT,
1059 Capability::RuntimeDescriptorArrayEXT,
1060 Capability::InputAttachmentArrayDynamicIndexingEXT,
1061 Capability::UniformTexelBufferArrayDynamicIndexingEXT,
1062 Capability::StorageTexelBufferArrayDynamicIndexingEXT,
1063 Capability::UniformBufferArrayNonUniformIndexingEXT,
1064 Capability::SampledImageArrayNonUniformIndexingEXT,
1065 Capability::StorageBufferArrayNonUniformIndexingEXT,
1066 Capability::StorageImageArrayNonUniformIndexingEXT,
1067 Capability::InputAttachmentArrayNonUniformIndexingEXT,
1068 Capability::UniformTexelBufferArrayNonUniformIndexingEXT,
1069 Capability::StorageTexelBufferArrayNonUniformIndexingEXT});
1070 }
1071
1072 // Became core in Vulkan 1.3
1073 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 6)))
1074 addAvailableCaps({Capability::StorageImageWriteWithoutFormat,
1075 Capability::StorageImageReadWithoutFormat});
1076}
1077
1078} // namespace SPIRV
1079} // namespace llvm
1080
1081// Add the required capabilities from a decoration instruction (including
1082// BuiltIns).
1083static void addOpDecorateReqs(const MachineInstr &MI, unsigned DecIndex,
1085 const SPIRVSubtarget &ST) {
1086 int64_t DecOp = MI.getOperand(DecIndex).getImm();
1087 auto Dec = static_cast<SPIRV::Decoration::Decoration>(DecOp);
1089 SPIRV::OperandCategory::DecorationOperand, Dec, ST, Reqs));
1090
1091 if (Dec == SPIRV::Decoration::BuiltIn) {
1092 int64_t BuiltInOp = MI.getOperand(DecIndex + 1).getImm();
1093 auto BuiltIn = static_cast<SPIRV::BuiltIn::BuiltIn>(BuiltInOp);
1095 SPIRV::OperandCategory::BuiltInOperand, BuiltIn, ST, Reqs));
1096 } else if (Dec == SPIRV::Decoration::LinkageAttributes) {
1097 int64_t LinkageOp = MI.getOperand(MI.getNumOperands() - 1).getImm();
1098 SPIRV::LinkageType::LinkageType LnkType =
1099 static_cast<SPIRV::LinkageType::LinkageType>(LinkageOp);
1100 if (LnkType == SPIRV::LinkageType::LinkOnceODR)
1101 Reqs.addExtension(SPIRV::Extension::SPV_KHR_linkonce_odr);
1102 else if (LnkType == SPIRV::LinkageType::WeakAMD) {
1103 Reqs.addExtension(SPIRV::Extension::SPV_AMD_weak_linkage);
1104 Reqs.addCapability(SPIRV::Capability::WeakLinkageAMD);
1105 }
1106 } else if (Dec == SPIRV::Decoration::CacheControlLoadINTEL ||
1107 Dec == SPIRV::Decoration::CacheControlStoreINTEL) {
1108 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_cache_controls);
1109 } else if (Dec == SPIRV::Decoration::HostAccessINTEL) {
1110 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_global_variable_host_access);
1111 } else if (Dec == SPIRV::Decoration::InitModeINTEL ||
1112 Dec == SPIRV::Decoration::ImplementInRegisterMapINTEL) {
1113 Reqs.addExtension(
1114 SPIRV::Extension::SPV_INTEL_global_variable_fpga_decorations);
1115 } else if (Dec == SPIRV::Decoration::NonUniformEXT) {
1116 Reqs.addRequirements(SPIRV::Capability::ShaderNonUniformEXT);
1117 } else if (Dec == SPIRV::Decoration::FPMaxErrorDecorationINTEL) {
1118 Reqs.addRequirements(SPIRV::Capability::FPMaxErrorINTEL);
1119 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_fp_max_error);
1120 } else if (Dec == SPIRV::Decoration::FPFastMathMode) {
1121 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2)) {
1122 Reqs.addRequirements(SPIRV::Capability::FloatControls2);
1123 Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls2);
1124 }
1125 }
1126}
1127
1128// Add requirements for image handling.
1131 const SPIRVSubtarget &ST) {
1132 assert(MI.getNumOperands() >= 8 && "Insufficient operands for OpTypeImage");
1133 // The operand indices used here are based on the OpTypeImage layout, which
1134 // the MachineInstr follows as well.
1135 int64_t ImgFormatOp = MI.getOperand(7).getImm();
1136 auto ImgFormat = static_cast<SPIRV::ImageFormat::ImageFormat>(ImgFormatOp);
1137 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ImageFormatOperand,
1138 ImgFormat, ST);
1139
1140 bool IsArrayed = MI.getOperand(4).getImm() == 1;
1141 bool IsMultisampled = MI.getOperand(5).getImm() == 1;
1142 bool NoSampler = MI.getOperand(6).getImm() == 2;
1143 // Add dimension requirements.
1144 assert(MI.getOperand(2).isImm());
1145 switch (MI.getOperand(2).getImm()) {
1146 case SPIRV::Dim::DIM_1D:
1147 Reqs.addRequirements(NoSampler ? SPIRV::Capability::Image1D
1148 : SPIRV::Capability::Sampled1D);
1149 break;
1150 case SPIRV::Dim::DIM_2D:
1151 if (IsMultisampled && NoSampler)
1152 Reqs.addRequirements(SPIRV::Capability::StorageImageMultisample);
1153 if (IsMultisampled && IsArrayed)
1154 Reqs.addRequirements(SPIRV::Capability::ImageMSArray);
1155 break;
1156 case SPIRV::Dim::DIM_3D:
1157 break;
1158 case SPIRV::Dim::DIM_Cube:
1159 Reqs.addRequirements(SPIRV::Capability::Shader);
1160 if (IsArrayed)
1161 Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageCubeArray
1162 : SPIRV::Capability::SampledCubeArray);
1163 break;
1164 case SPIRV::Dim::DIM_Rect:
1165 Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageRect
1166 : SPIRV::Capability::SampledRect);
1167 break;
1168 case SPIRV::Dim::DIM_Buffer:
1169 Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageBuffer
1170 : SPIRV::Capability::SampledBuffer);
1171 break;
1172 case SPIRV::Dim::DIM_SubpassData:
1173 Reqs.addRequirements(SPIRV::Capability::InputAttachment);
1174 break;
1175 }
1176
1177 // Has optional access qualifier.
1178 if (!ST.isShader()) {
1179 if (MI.getNumOperands() > 8 &&
1180 MI.getOperand(8).getImm() == SPIRV::AccessQualifier::ReadWrite)
1181 Reqs.addRequirements(SPIRV::Capability::ImageReadWrite);
1182 else
1183 Reqs.addRequirements(SPIRV::Capability::ImageBasic);
1184 }
1185}
1186
1187static bool isBFloat16Type(SPIRVTypeInst TypeDef) {
1188 return TypeDef && TypeDef->getNumOperands() == 3 &&
1189 TypeDef->getOpcode() == SPIRV::OpTypeFloat &&
1190 TypeDef->getOperand(1).getImm() == 16 &&
1191 TypeDef->getOperand(2).getImm() == SPIRV::FPEncoding::BFloat16KHR;
1192}
1193
1194// Add requirements for handling atomic float instructions
1195#define ATOM_FLT_REQ_EXT_MSG(ExtName) \
1196 "The atomic float instruction requires the following SPIR-V " \
1197 "extension: SPV_EXT_shader_atomic_float" ExtName
1200 const SPIRVSubtarget &ST) {
1201 SPIRVTypeInst VecTypeDef =
1202 MI.getMF()->getRegInfo().getVRegDef(MI.getOperand(1).getReg());
1203
1204 const unsigned Rank = VecTypeDef->getOperand(2).getImm();
1205 if (Rank != 2 && Rank != 4)
1206 reportFatalUsageError("Result type of an atomic vector float instruction "
1207 "must be a 2-component or 4 component vector");
1208
1209 SPIRVTypeInst EltTypeDef =
1210 MI.getMF()->getRegInfo().getVRegDef(VecTypeDef->getOperand(1).getReg());
1211
1212 if (EltTypeDef->getOpcode() != SPIRV::OpTypeFloat ||
1213 EltTypeDef->getOperand(1).getImm() != 16)
1215 "The element type for the result type of an atomic vector float "
1216 "instruction must be a 16-bit floating-point scalar");
1217
1218 // The extension is defined for fp16, but the AMD target lets a bf16 vector
1219 // use the same instruction so it can lower to a packed bf16 atomic.
1220 if (isBFloat16Type(EltTypeDef) &&
1221 ST.getTargetTriple().getVendor() != Triple::AMD)
1223 "The element type for the result type of an atomic vector float "
1224 "instruction cannot be a bfloat16 scalar");
1225 if (!ST.canUseExtension(SPIRV::Extension::SPV_NV_shader_atomic_fp16_vector))
1227 "The atomic float16 vector instruction requires the following SPIR-V "
1228 "extension: SPV_NV_shader_atomic_fp16_vector");
1229
1230 Reqs.addExtension(SPIRV::Extension::SPV_NV_shader_atomic_fp16_vector);
1231 Reqs.addCapability(SPIRV::Capability::AtomicFloat16VectorNV);
1232}
1233
1236 const SPIRVSubtarget &ST) {
1237 assert(MI.getOperand(1).isReg() &&
1238 "Expect register operand in atomic float instruction");
1239 Register TypeReg = MI.getOperand(1).getReg();
1240 SPIRVTypeInst TypeDef = MI.getMF()->getRegInfo().getVRegDef(TypeReg);
1241
1242 if (isVectorType(TypeDef))
1243 return AddAtomicVectorFloatRequirements(MI, Reqs, ST);
1244
1245 if (TypeDef->getOpcode() != SPIRV::OpTypeFloat)
1246 report_fatal_error("Result type of an atomic float instruction must be a "
1247 "floating-point type scalar");
1248
1249 unsigned BitWidth = TypeDef->getOperand(1).getImm();
1250 unsigned Op = MI.getOpcode();
1251 if (Op == SPIRV::OpAtomicFAddEXT) {
1252 if (!ST.canUseExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_add))
1254 Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_add);
1255 switch (BitWidth) {
1256 case 16:
1257 if (isBFloat16Type(TypeDef)) {
1258 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics))
1260 "The atomic bfloat16 instruction requires the following SPIR-V "
1261 "extension: SPV_INTEL_16bit_atomics",
1262 false);
1263 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics);
1264 Reqs.addCapability(SPIRV::Capability::AtomicBFloat16AddINTEL);
1265 } else {
1266 if (!ST.canUseExtension(
1267 SPIRV::Extension::SPV_EXT_shader_atomic_float16_add))
1268 report_fatal_error(ATOM_FLT_REQ_EXT_MSG("16_add"), false);
1269 Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float16_add);
1270 Reqs.addCapability(SPIRV::Capability::AtomicFloat16AddEXT);
1271 }
1272 break;
1273 case 32:
1274 Reqs.addCapability(SPIRV::Capability::AtomicFloat32AddEXT);
1275 break;
1276 case 64:
1277 Reqs.addCapability(SPIRV::Capability::AtomicFloat64AddEXT);
1278 break;
1279 default:
1281 "Unexpected floating-point type width in atomic float instruction");
1282 }
1283 } else {
1284 if (!ST.canUseExtension(
1285 SPIRV::Extension::SPV_EXT_shader_atomic_float_min_max))
1286 report_fatal_error(ATOM_FLT_REQ_EXT_MSG("_min_max"), false);
1287 Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_min_max);
1288 switch (BitWidth) {
1289 case 16:
1290 if (isBFloat16Type(TypeDef)) {
1291 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics))
1293 "The atomic bfloat16 instruction requires the following SPIR-V "
1294 "extension: SPV_INTEL_16bit_atomics",
1295 false);
1296 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics);
1297 Reqs.addCapability(SPIRV::Capability::AtomicBFloat16MinMaxINTEL);
1298 } else {
1299 Reqs.addCapability(SPIRV::Capability::AtomicFloat16MinMaxEXT);
1300 }
1301 break;
1302 case 32:
1303 Reqs.addCapability(SPIRV::Capability::AtomicFloat32MinMaxEXT);
1304 break;
1305 case 64:
1306 Reqs.addCapability(SPIRV::Capability::AtomicFloat64MinMaxEXT);
1307 break;
1308 default:
1310 "Unexpected floating-point type width in atomic float instruction");
1311 }
1312 }
1313}
1314
1316 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1317 return false;
1318 uint32_t Dim = ImageInst->getOperand(2).getImm();
1319 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1320 return Dim == SPIRV::Dim::DIM_Buffer && Sampled == 1;
1321}
1322
1324 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1325 return false;
1326 uint32_t Dim = ImageInst->getOperand(2).getImm();
1327 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1328 return Dim == SPIRV::Dim::DIM_Buffer && Sampled == 2;
1329}
1330
1332 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1333 return false;
1334 uint32_t Dim = ImageInst->getOperand(2).getImm();
1335 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1336 return Dim != SPIRV::Dim::DIM_Buffer && Sampled == 1;
1337}
1338
1340 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1341 return false;
1342 uint32_t Dim = ImageInst->getOperand(2).getImm();
1343 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1344 return Dim == SPIRV::Dim::DIM_SubpassData && Sampled == 2;
1345}
1346
1348 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1349 return false;
1350 uint32_t Dim = ImageInst->getOperand(2).getImm();
1351 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1352 return Dim != SPIRV::Dim::DIM_Buffer && Sampled == 2;
1353}
1354
1355bool isCombinedImageSampler(MachineInstr *SampledImageInst) {
1356 if (SampledImageInst->getOpcode() != SPIRV::OpTypeSampledImage)
1357 return false;
1358
1359 const MachineRegisterInfo &MRI = SampledImageInst->getMF()->getRegInfo();
1360 Register ImageReg = SampledImageInst->getOperand(1).getReg();
1361 auto *ImageInst = MRI.getUniqueVRegDef(ImageReg);
1362 return isSampledImage(ImageInst);
1363}
1364
1366 for (const auto &MI : MRI.reg_instructions(Reg)) {
1367 if (MI.getOpcode() != SPIRV::OpDecorate)
1368 continue;
1369
1370 uint32_t Dec = MI.getOperand(1).getImm();
1371 if (Dec == SPIRV::Decoration::NonUniformEXT)
1372 return true;
1373 }
1374 return false;
1375}
1376
1379 const SPIRVSubtarget &Subtarget) {
1380 const MachineRegisterInfo &MRI = Instr.getMF()->getRegInfo();
1381 // Get the result type. If it is an image type, then the shader uses
1382 // descriptor indexing. The appropriate capabilities will be added based
1383 // on the specifics of the image.
1384 Register ResTypeReg = Instr.getOperand(1).getReg();
1385 MachineInstr *ResTypeInst = MRI.getUniqueVRegDef(ResTypeReg);
1386
1387 assert(ResTypeInst->getOpcode() == SPIRV::OpTypePointer);
1388 uint32_t StorageClass = ResTypeInst->getOperand(1).getImm();
1389 if (StorageClass != SPIRV::StorageClass::StorageClass::UniformConstant &&
1390 StorageClass != SPIRV::StorageClass::StorageClass::Uniform &&
1391 StorageClass != SPIRV::StorageClass::StorageClass::StorageBuffer) {
1392 return;
1393 }
1394
1395 bool IsNonUniform =
1396 hasNonUniformDecoration(Instr.getOperand(0).getReg(), MRI);
1397
1398 auto FirstIndexReg = Instr.getOperand(3).getReg();
1399 bool FirstIndexIsConstant =
1400 Subtarget.getInstrInfo()->isConstantInstr(*MRI.getVRegDef(FirstIndexReg));
1401
1402 if (StorageClass == SPIRV::StorageClass::StorageClass::StorageBuffer) {
1403 if (IsNonUniform)
1404 Handler.addRequirements(
1405 SPIRV::Capability::StorageBufferArrayNonUniformIndexingEXT);
1406 else if (!FirstIndexIsConstant)
1407 Handler.addRequirements(
1408 SPIRV::Capability::StorageBufferArrayDynamicIndexing);
1409 return;
1410 }
1411
1412 Register PointeeTypeReg = ResTypeInst->getOperand(2).getReg();
1413 MachineInstr *PointeeType = MRI.getUniqueVRegDef(PointeeTypeReg);
1414 if (PointeeType->getOpcode() != SPIRV::OpTypeImage &&
1415 PointeeType->getOpcode() != SPIRV::OpTypeSampledImage &&
1416 PointeeType->getOpcode() != SPIRV::OpTypeSampler) {
1417 return;
1418 }
1419
1420 if (isUniformTexelBuffer(PointeeType)) {
1421 if (IsNonUniform)
1422 Handler.addRequirements(
1423 SPIRV::Capability::UniformTexelBufferArrayNonUniformIndexingEXT);
1424 else if (!FirstIndexIsConstant)
1425 Handler.addRequirements(
1426 SPIRV::Capability::UniformTexelBufferArrayDynamicIndexingEXT);
1427 } else if (isInputAttachment(PointeeType)) {
1428 if (IsNonUniform)
1429 Handler.addRequirements(
1430 SPIRV::Capability::InputAttachmentArrayNonUniformIndexingEXT);
1431 else if (!FirstIndexIsConstant)
1432 Handler.addRequirements(
1433 SPIRV::Capability::InputAttachmentArrayDynamicIndexingEXT);
1434 } else if (isStorageTexelBuffer(PointeeType)) {
1435 if (IsNonUniform)
1436 Handler.addRequirements(
1437 SPIRV::Capability::StorageTexelBufferArrayNonUniformIndexingEXT);
1438 else if (!FirstIndexIsConstant)
1439 Handler.addRequirements(
1440 SPIRV::Capability::StorageTexelBufferArrayDynamicIndexingEXT);
1441 } else if (isSampledImage(PointeeType) ||
1442 isCombinedImageSampler(PointeeType) ||
1443 PointeeType->getOpcode() == SPIRV::OpTypeSampler) {
1444 if (IsNonUniform)
1445 Handler.addRequirements(
1446 SPIRV::Capability::SampledImageArrayNonUniformIndexingEXT);
1447 else if (!FirstIndexIsConstant)
1448 Handler.addRequirements(
1449 SPIRV::Capability::SampledImageArrayDynamicIndexing);
1450 } else if (isStorageImage(PointeeType)) {
1451 if (IsNonUniform)
1452 Handler.addRequirements(
1453 SPIRV::Capability::StorageImageArrayNonUniformIndexingEXT);
1454 else if (!FirstIndexIsConstant)
1455 Handler.addRequirements(
1456 SPIRV::Capability::StorageImageArrayDynamicIndexing);
1457 }
1458}
1459
1461 if (TypeInst->getOpcode() != SPIRV::OpTypeImage)
1462 return false;
1463 assert(TypeInst->getOperand(7).isImm() && "The image format must be an imm.");
1464 return TypeInst->getOperand(7).getImm() == 0;
1465}
1466
1469 const SPIRVSubtarget &ST) {
1470 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product))
1471 Reqs.addExtension(SPIRV::Extension::SPV_KHR_integer_dot_product);
1472 Reqs.addCapability(SPIRV::Capability::DotProduct);
1473
1474 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1475 assert(MI.getOperand(2).isReg() && "Unexpected operand in dot");
1476 // We do not consider what the previous instruction is. This is just used
1477 // to get the input register and to check the type.
1478 const MachineInstr *Input = MRI.getVRegDef(MI.getOperand(2).getReg());
1479 assert(Input->getOperand(1).isReg() && "Unexpected operand in dot input");
1480 Register InputReg = Input->getOperand(1).getReg();
1481
1482 SPIRVTypeInst TypeDef = MRI.getVRegDef(InputReg);
1483 if (TypeDef->getOpcode() == SPIRV::OpTypeInt) {
1484 assert(TypeDef->getOperand(1).getImm() == 32);
1485 Reqs.addCapability(SPIRV::Capability::DotProductInput4x8BitPacked);
1486 } else if (isVectorType(TypeDef)) {
1487 SPIRVTypeInst ScalarTypeDef =
1488 MRI.getVRegDef(TypeDef->getOperand(1).getReg());
1489 assert(ScalarTypeDef->getOpcode() == SPIRV::OpTypeInt);
1490 if (ScalarTypeDef->getOperand(1).getImm() == 8) {
1491 assert(TypeDef->getOperand(2).getImm() == 4 &&
1492 "Dot operand of 8-bit integer type requires 4 components");
1493 Reqs.addCapability(SPIRV::Capability::DotProductInput4x8Bit);
1494 } else {
1495 Reqs.addCapability(SPIRV::Capability::DotProductInputAll);
1496 }
1497 }
1498}
1499
1502 const SPIRVSubtarget &ST) {
1503 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
1504 SPIRVTypeInst PtrType =
1505 GR->getSPIRVTypeForVReg(MI.getOperand(4).getReg(), MI.getMF());
1506 if (PtrType) {
1507 MachineOperand ASOp = PtrType->getOperand(1);
1508 if (ASOp.isImm()) {
1509 unsigned AddrSpace = ASOp.getImm();
1510 if (AddrSpace != SPIRV::StorageClass::UniformConstant) {
1511 if (!ST.canUseExtension(
1513 SPV_EXT_relaxed_printf_string_address_space)) {
1514 report_fatal_error("SPV_EXT_relaxed_printf_string_address_space is "
1515 "required because printf uses a format string not "
1516 "in constant address space.",
1517 false);
1518 }
1519 Reqs.addExtension(
1520 SPIRV::Extension::SPV_EXT_relaxed_printf_string_address_space);
1521 }
1522 }
1523 }
1524}
1525
1528 const SPIRVSubtarget &ST, unsigned OpIdx) {
1529 if (MI.getNumOperands() <= OpIdx)
1530 return;
1531 uint32_t Mask = MI.getOperand(OpIdx).getImm();
1532 for (uint32_t I = 0; I < 32; ++I)
1533 if (Mask & (1U << I))
1534 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ImageOperandOperand,
1535 1U << I, ST);
1536}
1537
1538static inline void maybeAddScatterGatherReq(const MachineInstr &MI,
1540 const SPIRVSubtarget &ST) {
1541 assert(MI.getOperand(1).isReg());
1542 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1543 SPIRVTypeInst ElemTypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
1544 if (ElemTypeDef->getOpcode() == SPIRV::OpTypePointer &&
1545 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
1546 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_masked_gather_scatter);
1547 Reqs.addCapability(SPIRV::Capability::MaskedGatherScatterINTEL);
1548 }
1549}
1550
1553 const SPIRVSubtarget &ST) {
1554 SPIRV::RequirementHandler &Reqs = MAI.Reqs;
1555 unsigned Op = MI.getOpcode();
1556 switch (Op) {
1557 case SPIRV::OpMemoryModel: {
1558 int64_t Addr = MI.getOperand(0).getImm();
1559 Reqs.getAndAddRequirements(SPIRV::OperandCategory::AddressingModelOperand,
1560 Addr, ST);
1561 int64_t Mem = MI.getOperand(1).getImm();
1562 Reqs.getAndAddRequirements(SPIRV::OperandCategory::MemoryModelOperand, Mem,
1563 ST);
1564 break;
1565 }
1566 case SPIRV::OpEntryPoint: {
1567 int64_t Exe = MI.getOperand(0).getImm();
1568 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ExecutionModelOperand,
1569 Exe, ST);
1570 break;
1571 }
1572 case SPIRV::OpExecutionMode:
1573 case SPIRV::OpExecutionModeId: {
1574 int64_t Exe = MI.getOperand(1).getImm();
1575 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ExecutionModeOperand,
1576 Exe, ST);
1577 break;
1578 }
1579 case SPIRV::OpTypeMatrix:
1580 Reqs.addCapability(SPIRV::Capability::Matrix);
1581 break;
1582 case SPIRV::OpTypeInt: {
1583 unsigned BitWidth = MI.getOperand(1).getImm();
1584 if (BitWidth == 64)
1585 Reqs.addCapability(SPIRV::Capability::Int64);
1586 else if (BitWidth == 16)
1587 Reqs.addCapability(SPIRV::Capability::Int16);
1588 else if (BitWidth == 8)
1589 Reqs.addCapability(SPIRV::Capability::Int8);
1590 else if (BitWidth == 4 &&
1591 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_int4)) {
1592 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_int4);
1593 Reqs.addCapability(SPIRV::Capability::Int4TypeINTEL);
1594 } else if (BitWidth != 32) {
1595 if (!ST.canUseExtension(
1596 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers))
1598 "OpTypeInt type with a width other than 8, 16, 32 or 64 bits "
1599 "requires the following SPIR-V extension: "
1600 "SPV_ALTERA_arbitrary_precision_integers");
1601 Reqs.addExtension(
1602 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers);
1603 Reqs.addCapability(SPIRV::Capability::ArbitraryPrecisionIntegersALTERA);
1604 }
1605 break;
1606 }
1607 case SPIRV::OpDot: {
1608 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1609 SPIRVTypeInst TypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
1610 if (isBFloat16Type(TypeDef))
1611 Reqs.addCapability(SPIRV::Capability::BFloat16DotProductKHR);
1612 break;
1613 }
1614 case SPIRV::OpTypeFloat: {
1615 unsigned BitWidth = MI.getOperand(1).getImm();
1616 if (BitWidth == 64)
1617 Reqs.addCapability(SPIRV::Capability::Float64);
1618 else if (BitWidth == 16) {
1619 if (isBFloat16Type(&MI)) {
1620 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_bfloat16))
1621 report_fatal_error("OpTypeFloat type with bfloat requires the "
1622 "following SPIR-V extension: SPV_KHR_bfloat16",
1623 false);
1624 Reqs.addExtension(SPIRV::Extension::SPV_KHR_bfloat16);
1625 Reqs.addCapability(SPIRV::Capability::BFloat16TypeKHR);
1626 } else {
1627 Reqs.addCapability(SPIRV::Capability::Float16);
1628 }
1629 }
1630 break;
1631 }
1632 case SPIRV::OpTypeVector: {
1633 unsigned NumComponents = MI.getOperand(2).getImm();
1634 if (NumComponents == 8 || NumComponents == 16)
1635 Reqs.addCapability(SPIRV::Capability::Vector16);
1636 else if (requiresLongVectorEXT(NumComponents))
1637 // Such widths are only expressible as OpTypeVectorIdEXT.
1639 "OpTypeVector with " + Twine(NumComponents) +
1640 " components requires the following SPIR-V extension: "
1641 "SPV_EXT_long_vector");
1642
1643 maybeAddScatterGatherReq(MI, Reqs, ST);
1644 break;
1645 }
1646 case SPIRV::OpTypeVectorIdEXT: {
1647 if (!ST.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector))
1648 reportFatalUsageError("OpTypeVectorIdEXT requires the following SPIR-V "
1649 "extension: SPV_EXT_long_vector extension");
1650 Reqs.addExtension(SPIRV::Extension::SPV_EXT_long_vector);
1651 Reqs.addCapability(SPIRV::Capability::LongVectorEXT);
1652 maybeAddScatterGatherReq(MI, Reqs, ST);
1653 break;
1654 }
1655 case SPIRV::OpTypePointer: {
1656 auto SC = MI.getOperand(1).getImm();
1657 Reqs.getAndAddRequirements(SPIRV::OperandCategory::StorageClassOperand, SC,
1658 ST);
1659 // If it's a type of pointer to float16 targeting OpenCL, add Float16Buffer
1660 // capability.
1661 if (ST.isShader())
1662 break;
1663 assert(MI.getOperand(2).isReg());
1664 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1665 SPIRVTypeInst TypeDef = MRI.getVRegDef(MI.getOperand(2).getReg());
1666 if ((TypeDef->getNumOperands() == 2) &&
1667 (TypeDef->getOpcode() == SPIRV::OpTypeFloat) &&
1668 (TypeDef->getOperand(1).getImm() == 16))
1669 Reqs.addCapability(SPIRV::Capability::Float16Buffer);
1670 break;
1671 }
1672 case SPIRV::OpExtInst: {
1673 if (MI.getOperand(2).getImm() ==
1674 static_cast<int64_t>(
1675 SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100)) {
1676 Reqs.addExtension(SPIRV::Extension::SPV_KHR_non_semantic_info);
1677 break;
1678 }
1679 if (MI.getOperand(3).getImm() ==
1680 static_cast<int64_t>(SPIRV::OpenCLExtInst::printf)) {
1681 addPrintfRequirements(MI, Reqs, ST);
1682 break;
1683 }
1684 if (MI.getOperand(2).getImm() ==
1685 static_cast<int64_t>(SPIRV::InstructionSet::OpenCL_std)) {
1686 const MachineFunction *MF = MI.getMF();
1687 const MachineRegisterInfo &MRI = MF->getRegInfo();
1688 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
1689
1690 auto IsBFloat16 = [&](SPIRVTypeInst TypeDef) {
1691 if (TypeDef && TypeDef->getOpcode() == SPIRV::OpTypeVector)
1692 TypeDef = MRI.getVRegDef(TypeDef->getOperand(1).getReg());
1693 return isBFloat16Type(TypeDef);
1694 };
1695
1696 // Result type is operand 1; arguments start at operand 4.
1697 bool UsesBFloat16 = IsBFloat16(MRI.getVRegDef(MI.getOperand(1).getReg()));
1698 for (unsigned I = 4, E = MI.getNumOperands(); I < E && !UsesBFloat16;
1699 ++I) {
1700 const MachineOperand &MO = MI.getOperand(I);
1701 if (MO.isReg())
1702 UsesBFloat16 = IsBFloat16(GR->getResultType(
1703 MO.getReg(), const_cast<MachineFunction *>(MF)));
1704 }
1705
1706 if (UsesBFloat16) {
1707 if (!ST.canUseExtension(
1708 SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic)) {
1709 reportUnsupported(
1710 MI, "OpenCL Extended instructions with bfloat16 require the "
1711 "following SPIR-V extension: SPV_INTEL_bfloat16_arithmetic");
1712 break;
1713 }
1714 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic);
1715 Reqs.addCapability(SPIRV::Capability::BFloat16ArithmeticINTEL);
1716 }
1717 }
1718 break;
1719 }
1720 case SPIRV::OpAliasDomainDeclINTEL:
1721 case SPIRV::OpAliasScopeDeclINTEL:
1722 case SPIRV::OpAliasScopeListDeclINTEL: {
1723 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing);
1724 Reqs.addCapability(SPIRV::Capability::MemoryAccessAliasingINTEL);
1725 break;
1726 }
1727 case SPIRV::OpBitReverse:
1728 case SPIRV::OpBitFieldInsert:
1729 case SPIRV::OpBitFieldSExtract:
1730 case SPIRV::OpBitFieldUExtract:
1731 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions)) {
1732 Reqs.addCapability(SPIRV::Capability::Shader);
1733 break;
1734 }
1735 Reqs.addExtension(SPIRV::Extension::SPV_KHR_bit_instructions);
1736 Reqs.addCapability(SPIRV::Capability::BitInstructions);
1737 break;
1738 case SPIRV::OpTypeRuntimeArray:
1739 Reqs.addCapability(SPIRV::Capability::Shader);
1740 break;
1741 case SPIRV::OpTypeOpaque:
1742 case SPIRV::OpTypeEvent:
1743 Reqs.addCapability(SPIRV::Capability::Kernel);
1744 break;
1745 case SPIRV::OpTypePipe:
1746 case SPIRV::OpTypeReserveId:
1747 Reqs.addCapability(SPIRV::Capability::Pipes);
1748 break;
1749 case SPIRV::OpTypeDeviceEvent:
1750 case SPIRV::OpTypeQueue:
1751 case SPIRV::OpBuildNDRange:
1752 case SPIRV::OpEnqueueKernel:
1753 Reqs.addCapability(SPIRV::Capability::DeviceEnqueue);
1754 break;
1755 case SPIRV::OpDecorate:
1756 case SPIRV::OpDecorateId:
1757 case SPIRV::OpDecorateString:
1758 addOpDecorateReqs(MI, 1, Reqs, ST);
1759 break;
1760 case SPIRV::OpMemberDecorate:
1761 case SPIRV::OpMemberDecorateString:
1762 addOpDecorateReqs(MI, 2, Reqs, ST);
1763 break;
1764 case SPIRV::OpInBoundsPtrAccessChain:
1765 Reqs.addCapability(SPIRV::Capability::Addresses);
1766 break;
1767 case SPIRV::OpConstantSampler:
1768 Reqs.addCapability(SPIRV::Capability::LiteralSampler);
1769 break;
1770 case SPIRV::OpInBoundsAccessChain:
1771 case SPIRV::OpAccessChain:
1772 addOpAccessChainReqs(MI, Reqs, ST);
1773 break;
1774 case SPIRV::OpTypeImage:
1775 addOpTypeImageReqs(MI, Reqs, ST);
1776 break;
1777 case SPIRV::OpTypeSampler:
1778 if (!ST.isShader()) {
1779 Reqs.addCapability(SPIRV::Capability::ImageBasic);
1780 }
1781 break;
1782 case SPIRV::OpTypeForwardPointer:
1783 // TODO: check if it's OpenCL's kernel.
1784 Reqs.addCapability(SPIRV::Capability::Addresses);
1785 break;
1786 case SPIRV::OpAtomicFlagTestAndSet:
1787 case SPIRV::OpAtomicLoad:
1788 case SPIRV::OpAtomicStore:
1789 case SPIRV::OpAtomicExchange:
1790 case SPIRV::OpAtomicCompareExchange:
1791 case SPIRV::OpAtomicCompareExchangeWeak:
1792 case SPIRV::OpAtomicIIncrement:
1793 case SPIRV::OpAtomicIDecrement:
1794 case SPIRV::OpAtomicIAdd:
1795 case SPIRV::OpAtomicISub:
1796 case SPIRV::OpAtomicUMin:
1797 case SPIRV::OpAtomicUMax:
1798 case SPIRV::OpAtomicSMin:
1799 case SPIRV::OpAtomicSMax:
1800 case SPIRV::OpAtomicAnd:
1801 case SPIRV::OpAtomicOr:
1802 case SPIRV::OpAtomicXor: {
1803 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1804 const MachineInstr *InstrPtr = &MI;
1805 if (Op == SPIRV::OpAtomicStore) {
1806 assert(MI.getOperand(3).isReg());
1807 InstrPtr = MRI.getVRegDef(MI.getOperand(3).getReg());
1808 assert(InstrPtr && "Unexpected type instruction for OpAtomicStore");
1809 }
1810 assert(InstrPtr->getOperand(1).isReg() && "Unexpected operand in atomic");
1811 Register TypeReg = InstrPtr->getOperand(1).getReg();
1812 SPIRVTypeInst TypeDef = MRI.getVRegDef(TypeReg);
1813
1814 if (TypeDef->getOpcode() == SPIRV::OpTypeInt) {
1815 unsigned BitWidth = TypeDef->getOperand(1).getImm();
1816 if (BitWidth == 64)
1817 Reqs.addCapability(SPIRV::Capability::Int64Atomics);
1818 else if (BitWidth == 16) {
1819 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics))
1821 "16-bit integer atomic operations require the following SPIR-V "
1822 "extension: SPV_INTEL_16bit_atomics",
1823 false);
1824 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics);
1825 switch (Op) {
1826 case SPIRV::OpAtomicLoad:
1827 case SPIRV::OpAtomicStore:
1828 case SPIRV::OpAtomicExchange:
1829 case SPIRV::OpAtomicCompareExchange:
1830 case SPIRV::OpAtomicCompareExchangeWeak:
1831 Reqs.addCapability(
1832 SPIRV::Capability::AtomicInt16CompareExchangeINTEL);
1833 break;
1834 default:
1835 Reqs.addCapability(SPIRV::Capability::Int16AtomicsINTEL);
1836 break;
1837 }
1838 }
1839 } else if (isBFloat16Type(TypeDef)) {
1840 if (is_contained({SPIRV::OpAtomicLoad, SPIRV::OpAtomicStore,
1841 SPIRV::OpAtomicExchange},
1842 Op)) {
1843 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics))
1845 "The atomic bfloat16 instruction requires the following SPIR-V "
1846 "extension: SPV_INTEL_16bit_atomics",
1847 false);
1848 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics);
1849 Reqs.addCapability(SPIRV::Capability::AtomicBFloat16LoadStoreINTEL);
1850 }
1851 }
1852 break;
1853 }
1854 case SPIRV::OpGroupNonUniformIAdd:
1855 case SPIRV::OpGroupNonUniformFAdd:
1856 case SPIRV::OpGroupNonUniformIMul:
1857 case SPIRV::OpGroupNonUniformFMul:
1858 case SPIRV::OpGroupNonUniformSMin:
1859 case SPIRV::OpGroupNonUniformUMin:
1860 case SPIRV::OpGroupNonUniformFMin:
1861 case SPIRV::OpGroupNonUniformSMax:
1862 case SPIRV::OpGroupNonUniformUMax:
1863 case SPIRV::OpGroupNonUniformFMax:
1864 case SPIRV::OpGroupNonUniformBitwiseAnd:
1865 case SPIRV::OpGroupNonUniformBitwiseOr:
1866 case SPIRV::OpGroupNonUniformBitwiseXor:
1867 case SPIRV::OpGroupNonUniformLogicalAnd:
1868 case SPIRV::OpGroupNonUniformLogicalOr:
1869 case SPIRV::OpGroupNonUniformLogicalXor: {
1870 assert(MI.getOperand(3).isImm());
1871 int64_t GroupOp = MI.getOperand(3).getImm();
1872 switch (GroupOp) {
1873 case SPIRV::GroupOperation::Reduce:
1874 case SPIRV::GroupOperation::InclusiveScan:
1875 case SPIRV::GroupOperation::ExclusiveScan:
1876 Reqs.addCapability(SPIRV::Capability::GroupNonUniformArithmetic);
1877 break;
1878 case SPIRV::GroupOperation::ClusteredReduce:
1879 Reqs.addCapability(SPIRV::Capability::GroupNonUniformClustered);
1880 break;
1881 case SPIRV::GroupOperation::PartitionedReduceNV:
1882 case SPIRV::GroupOperation::PartitionedInclusiveScanNV:
1883 case SPIRV::GroupOperation::PartitionedExclusiveScanNV:
1884 Reqs.addCapability(SPIRV::Capability::GroupNonUniformPartitionedNV);
1885 break;
1886 }
1887 break;
1888 }
1889 case SPIRV::OpGroupNonUniformQuadSwap:
1890 Reqs.addCapability(SPIRV::Capability::GroupNonUniformQuad);
1891 break;
1892 case SPIRV::OpImageQueryLod:
1893 Reqs.addCapability(SPIRV::Capability::ImageQuery);
1894 break;
1895 case SPIRV::OpImageQuerySize:
1896 case SPIRV::OpImageQuerySizeLod:
1897 case SPIRV::OpImageQueryLevels:
1898 case SPIRV::OpImageQuerySamples:
1899 if (ST.isShader())
1900 Reqs.addCapability(SPIRV::Capability::ImageQuery);
1901 break;
1902 case SPIRV::OpImageQueryFormat: {
1903 Register ResultReg = MI.getOperand(0).getReg();
1904 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1905 static const unsigned CompareOps[] = {
1906 SPIRV::OpIEqual, SPIRV::OpINotEqual,
1907 SPIRV::OpUGreaterThan, SPIRV::OpUGreaterThanEqual,
1908 SPIRV::OpULessThan, SPIRV::OpULessThanEqual,
1909 SPIRV::OpSGreaterThan, SPIRV::OpSGreaterThanEqual,
1910 SPIRV::OpSLessThan, SPIRV::OpSLessThanEqual};
1911
1912 auto CheckAndAddExtension = [&](int64_t ImmVal) {
1913 if (ImmVal == 4323 || ImmVal == 4324) {
1914 if (ST.canUseExtension(SPIRV::Extension::SPV_EXT_image_raw10_raw12))
1915 Reqs.addExtension(SPIRV::Extension::SPV_EXT_image_raw10_raw12);
1916 else
1917 report_fatal_error("This requires the "
1918 "SPV_EXT_image_raw10_raw12 extension");
1919 }
1920 };
1921
1922 for (MachineInstr &UseInst : MRI.use_instructions(ResultReg)) {
1923 unsigned Opc = UseInst.getOpcode();
1924
1925 if (Opc == SPIRV::OpSwitch) {
1926 for (const MachineOperand &Op : UseInst.operands())
1927 if (Op.isImm())
1928 CheckAndAddExtension(Op.getImm());
1929 } else if (llvm::is_contained(CompareOps, Opc)) {
1930 for (unsigned i = 1; i < UseInst.getNumOperands(); ++i) {
1931 Register UseReg = UseInst.getOperand(i).getReg();
1932 MachineInstr *ConstInst = MRI.getVRegDef(UseReg);
1933 if (ConstInst && ConstInst->getOpcode() == SPIRV::OpConstantI) {
1934 int64_t ImmVal = ConstInst->getOperand(2).getImm();
1935 if (ImmVal)
1936 CheckAndAddExtension(ImmVal);
1937 }
1938 }
1939 }
1940 }
1941 break;
1942 }
1943
1944 case SPIRV::OpGroupNonUniformShuffle:
1945 case SPIRV::OpGroupNonUniformShuffleXor:
1946 Reqs.addCapability(SPIRV::Capability::GroupNonUniformShuffle);
1947 break;
1948 case SPIRV::OpGroupNonUniformShuffleUp:
1949 case SPIRV::OpGroupNonUniformShuffleDown:
1950 Reqs.addCapability(SPIRV::Capability::GroupNonUniformShuffleRelative);
1951 break;
1952 case SPIRV::OpGroupAll:
1953 case SPIRV::OpGroupAny:
1954 case SPIRV::OpGroupBroadcast:
1955 case SPIRV::OpGroupIAdd:
1956 case SPIRV::OpGroupFAdd:
1957 case SPIRV::OpGroupFMin:
1958 case SPIRV::OpGroupUMin:
1959 case SPIRV::OpGroupSMin:
1960 case SPIRV::OpGroupFMax:
1961 case SPIRV::OpGroupUMax:
1962 case SPIRV::OpGroupSMax:
1963 Reqs.addCapability(SPIRV::Capability::Groups);
1964 break;
1965 case SPIRV::OpGroupNonUniformElect:
1966 Reqs.addCapability(SPIRV::Capability::GroupNonUniform);
1967 break;
1968 case SPIRV::OpGroupNonUniformAll:
1969 case SPIRV::OpGroupNonUniformAny:
1970 case SPIRV::OpGroupNonUniformAllEqual:
1971 Reqs.addCapability(SPIRV::Capability::GroupNonUniformVote);
1972 break;
1973 case SPIRV::OpGroupNonUniformBroadcast:
1974 case SPIRV::OpGroupNonUniformBroadcastFirst:
1975 case SPIRV::OpGroupNonUniformBallot:
1976 case SPIRV::OpGroupNonUniformInverseBallot:
1977 case SPIRV::OpGroupNonUniformBallotBitExtract:
1978 case SPIRV::OpGroupNonUniformBallotBitCount:
1979 case SPIRV::OpGroupNonUniformBallotFindLSB:
1980 case SPIRV::OpGroupNonUniformBallotFindMSB:
1981 Reqs.addCapability(SPIRV::Capability::GroupNonUniformBallot);
1982 break;
1983 case SPIRV::OpSubgroupShuffleINTEL:
1984 case SPIRV::OpSubgroupShuffleDownINTEL:
1985 case SPIRV::OpSubgroupShuffleUpINTEL:
1986 case SPIRV::OpSubgroupShuffleXorINTEL:
1987 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
1988 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
1989 Reqs.addCapability(SPIRV::Capability::SubgroupShuffleINTEL);
1990 }
1991 break;
1992 case SPIRV::OpSubgroupBlockReadINTEL:
1993 case SPIRV::OpSubgroupBlockWriteINTEL:
1994 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
1995 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
1996 Reqs.addCapability(SPIRV::Capability::SubgroupBufferBlockIOINTEL);
1997 }
1998 break;
1999 case SPIRV::OpSubgroupImageBlockReadINTEL:
2000 case SPIRV::OpSubgroupImageBlockWriteINTEL:
2001 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
2002 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
2003 Reqs.addCapability(SPIRV::Capability::SubgroupImageBlockIOINTEL);
2004 }
2005 break;
2006 case SPIRV::OpSubgroupImageMediaBlockReadINTEL:
2007 case SPIRV::OpSubgroupImageMediaBlockWriteINTEL:
2008 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_media_block_io)) {
2009 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_media_block_io);
2010 Reqs.addCapability(SPIRV::Capability::SubgroupImageMediaBlockIOINTEL);
2011 }
2012 break;
2013 case SPIRV::OpAssumeTrueKHR:
2014 case SPIRV::OpExpectKHR:
2015 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) {
2016 Reqs.addExtension(SPIRV::Extension::SPV_KHR_expect_assume);
2017 Reqs.addCapability(SPIRV::Capability::ExpectAssumeKHR);
2018 }
2019 break;
2020 case SPIRV::OpFmaKHR:
2021 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_fma)) {
2022 Reqs.addExtension(SPIRV::Extension::SPV_KHR_fma);
2023 Reqs.addCapability(SPIRV::Capability::FmaKHR);
2024 }
2025 break;
2026 case SPIRV::OpPtrCastToCrossWorkgroupINTEL:
2027 case SPIRV::OpCrossWorkgroupCastToPtrINTEL:
2028 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes)) {
2029 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes);
2030 Reqs.addCapability(SPIRV::Capability::USMStorageClassesINTEL);
2031 }
2032 break;
2033 case SPIRV::OpConstantFunctionPointerINTEL:
2034 case SPIRV::OpFunctionPointerCallINTEL:
2035 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)) {
2036 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
2037 Reqs.addCapability(SPIRV::Capability::FunctionPointersINTEL);
2038 }
2039 break;
2040 case SPIRV::OpGroupNonUniformRotateKHR:
2041 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_subgroup_rotate))
2042 report_fatal_error("OpGroupNonUniformRotateKHR instruction requires the "
2043 "following SPIR-V extension: SPV_KHR_subgroup_rotate",
2044 false);
2045 Reqs.addExtension(SPIRV::Extension::SPV_KHR_subgroup_rotate);
2046 Reqs.addCapability(SPIRV::Capability::GroupNonUniformRotateKHR);
2047 Reqs.addCapability(SPIRV::Capability::GroupNonUniform);
2048 break;
2049 case SPIRV::OpFixedCosALTERA:
2050 case SPIRV::OpFixedSinALTERA:
2051 case SPIRV::OpFixedCosPiALTERA:
2052 case SPIRV::OpFixedSinPiALTERA:
2053 case SPIRV::OpFixedExpALTERA:
2054 case SPIRV::OpFixedLogALTERA:
2055 case SPIRV::OpFixedRecipALTERA:
2056 case SPIRV::OpFixedSqrtALTERA:
2057 case SPIRV::OpFixedSinCosALTERA:
2058 case SPIRV::OpFixedSinCosPiALTERA:
2059 case SPIRV::OpFixedRsqrtALTERA:
2060 if (!ST.canUseExtension(
2061 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_fixed_point))
2062 report_fatal_error("This instruction requires the "
2063 "following SPIR-V extension: "
2064 "SPV_ALTERA_arbitrary_precision_fixed_point",
2065 false);
2066 Reqs.addExtension(
2067 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_fixed_point);
2068 Reqs.addCapability(SPIRV::Capability::ArbitraryPrecisionFixedPointALTERA);
2069 break;
2070 case SPIRV::OpGroupIMulKHR:
2071 case SPIRV::OpGroupFMulKHR:
2072 case SPIRV::OpGroupBitwiseAndKHR:
2073 case SPIRV::OpGroupBitwiseOrKHR:
2074 case SPIRV::OpGroupBitwiseXorKHR:
2075 case SPIRV::OpGroupLogicalAndKHR:
2076 case SPIRV::OpGroupLogicalOrKHR:
2077 case SPIRV::OpGroupLogicalXorKHR:
2078 if (ST.canUseExtension(
2079 SPIRV::Extension::SPV_KHR_uniform_group_instructions)) {
2080 Reqs.addExtension(SPIRV::Extension::SPV_KHR_uniform_group_instructions);
2081 Reqs.addCapability(SPIRV::Capability::GroupUniformArithmeticKHR);
2082 }
2083 break;
2084 case SPIRV::OpReadClockKHR:
2085 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_shader_clock))
2086 report_fatal_error("OpReadClockKHR instruction requires the "
2087 "following SPIR-V extension: SPV_KHR_shader_clock",
2088 false);
2089 Reqs.addExtension(SPIRV::Extension::SPV_KHR_shader_clock);
2090 Reqs.addCapability(SPIRV::Capability::ShaderClockKHR);
2091 break;
2092 case SPIRV::OpAbortKHR:
2093 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort))
2094 report_fatal_error("OpAbortKHR instruction requires the "
2095 "following SPIR-V extension: SPV_KHR_abort",
2096 false);
2097 Reqs.addExtension(SPIRV::Extension::SPV_KHR_abort);
2098 Reqs.addCapability(SPIRV::Capability::AbortKHR);
2099 break;
2100 case SPIRV::OpPoisonKHR:
2101 case SPIRV::OpFreezeKHR:
2102 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_poison_freeze))
2103 report_fatal_error("OpPoisonKHR/OpFreezeKHR instruction requires the "
2104 "following SPIR-V extension: SPV_KHR_poison_freeze",
2105 false);
2106 Reqs.addExtension(SPIRV::Extension::SPV_KHR_poison_freeze);
2107 Reqs.addCapability(SPIRV::Capability::PoisonFreezeKHR);
2108 break;
2109 case SPIRV::OpAtomicFAddEXT:
2110 case SPIRV::OpAtomicFMinEXT:
2111 case SPIRV::OpAtomicFMaxEXT:
2112 AddAtomicFloatRequirements(MI, Reqs, ST);
2113 break;
2114 case SPIRV::OpConvertBF16ToFINTEL:
2115 case SPIRV::OpConvertFToBF16INTEL:
2116 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bfloat16_conversion)) {
2117 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_conversion);
2118 Reqs.addCapability(SPIRV::Capability::BFloat16ConversionINTEL);
2119 }
2120 break;
2121 case SPIRV::OpRoundFToTF32INTEL:
2122 if (ST.canUseExtension(
2123 SPIRV::Extension::SPV_INTEL_tensor_float32_conversion)) {
2124 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_tensor_float32_conversion);
2125 Reqs.addCapability(SPIRV::Capability::TensorFloat32RoundingINTEL);
2126 }
2127 break;
2128 case SPIRV::OpVariableLengthArrayINTEL:
2129 case SPIRV::OpSaveMemoryINTEL:
2130 case SPIRV::OpRestoreMemoryINTEL:
2131 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array)) {
2132 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_variable_length_array);
2133 Reqs.addCapability(SPIRV::Capability::VariableLengthArrayINTEL);
2134 }
2135 break;
2136 case SPIRV::OpAsmTargetINTEL:
2137 case SPIRV::OpAsmINTEL:
2138 case SPIRV::OpAsmCallINTEL:
2139 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_inline_assembly)) {
2140 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_inline_assembly);
2141 Reqs.addCapability(SPIRV::Capability::AsmINTEL);
2142 }
2143 break;
2144 case SPIRV::OpTypeCooperativeMatrixKHR: {
2145 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix))
2147 "OpTypeCooperativeMatrixKHR type requires the "
2148 "following SPIR-V extension: SPV_KHR_cooperative_matrix",
2149 false);
2150 Reqs.addExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix);
2151 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixKHR);
2152 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
2153 SPIRVTypeInst TypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
2154 if (isBFloat16Type(TypeDef))
2155 Reqs.addCapability(SPIRV::Capability::BFloat16CooperativeMatrixKHR);
2156 break;
2157 }
2158 case SPIRV::OpArithmeticFenceEXT:
2159 if (!ST.canUseExtension(SPIRV::Extension::SPV_EXT_arithmetic_fence))
2160 report_fatal_error("OpArithmeticFenceEXT requires the "
2161 "following SPIR-V extension: SPV_EXT_arithmetic_fence",
2162 false);
2163 Reqs.addExtension(SPIRV::Extension::SPV_EXT_arithmetic_fence);
2164 Reqs.addCapability(SPIRV::Capability::ArithmeticFenceEXT);
2165 break;
2166 case SPIRV::OpControlBarrierArriveINTEL:
2167 case SPIRV::OpControlBarrierWaitINTEL:
2168 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_split_barrier)) {
2169 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_split_barrier);
2170 Reqs.addCapability(SPIRV::Capability::SplitBarrierINTEL);
2171 }
2172 break;
2173 case SPIRV::OpCooperativeMatrixMulAddKHR: {
2174 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix))
2175 report_fatal_error("Cooperative matrix instructions require the "
2176 "following SPIR-V extension: "
2177 "SPV_KHR_cooperative_matrix",
2178 false);
2179 Reqs.addExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix);
2180 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixKHR);
2181 constexpr unsigned MulAddMaxSize = 6;
2182 if (MI.getNumOperands() != MulAddMaxSize)
2183 break;
2184 const int64_t CoopOperands = MI.getOperand(MulAddMaxSize - 1).getImm();
2185 if (CoopOperands &
2186 SPIRV::CooperativeMatrixOperands::MatrixAAndBTF32ComponentsINTEL) {
2187 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2188 report_fatal_error("MatrixAAndBTF32ComponentsINTEL type interpretation "
2189 "require the following SPIR-V extension: "
2190 "SPV_INTEL_joint_matrix",
2191 false);
2192 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2193 Reqs.addCapability(
2194 SPIRV::Capability::CooperativeMatrixTF32ComponentTypeINTEL);
2195 }
2196 if (CoopOperands & SPIRV::CooperativeMatrixOperands::
2197 MatrixAAndBBFloat16ComponentsINTEL ||
2198 CoopOperands &
2199 SPIRV::CooperativeMatrixOperands::MatrixCBFloat16ComponentsINTEL ||
2200 CoopOperands & SPIRV::CooperativeMatrixOperands::
2201 MatrixResultBFloat16ComponentsINTEL) {
2202 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2203 report_fatal_error("***BF16ComponentsINTEL type interpretations "
2204 "require the following SPIR-V extension: "
2205 "SPV_INTEL_joint_matrix",
2206 false);
2207 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2208 Reqs.addCapability(
2209 SPIRV::Capability::CooperativeMatrixBFloat16ComponentTypeINTEL);
2210 }
2211 break;
2212 }
2213 case SPIRV::OpCooperativeMatrixLoadKHR:
2214 case SPIRV::OpCooperativeMatrixStoreKHR:
2215 case SPIRV::OpCooperativeMatrixLoadCheckedINTEL:
2216 case SPIRV::OpCooperativeMatrixStoreCheckedINTEL:
2217 case SPIRV::OpCooperativeMatrixPrefetchINTEL: {
2218 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix))
2219 report_fatal_error("Cooperative matrix instructions require the "
2220 "following SPIR-V extension: "
2221 "SPV_KHR_cooperative_matrix",
2222 false);
2223 Reqs.addExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix);
2224 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixKHR);
2225
2226 // Check Layout operand in case if it's not a standard one and add the
2227 // appropriate capability.
2228 unsigned LayoutNum;
2229 switch (Op) {
2230 case SPIRV::OpCooperativeMatrixLoadKHR:
2231 LayoutNum = 3;
2232 break;
2233 case SPIRV::OpCooperativeMatrixStoreKHR:
2234 LayoutNum = 2;
2235 break;
2236 case SPIRV::OpCooperativeMatrixLoadCheckedINTEL:
2237 LayoutNum = 5;
2238 break;
2239 case SPIRV::OpCooperativeMatrixStoreCheckedINTEL:
2240 case SPIRV::OpCooperativeMatrixPrefetchINTEL:
2241 LayoutNum = 4;
2242 break;
2243 default:
2244 llvm_unreachable("unexpected cooperative matrix opcode");
2245 }
2246 Register RegLayout = MI.getOperand(LayoutNum).getReg();
2247 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
2248 MachineInstr *MILayout = MRI.getUniqueVRegDef(RegLayout);
2249 if (MILayout->getOpcode() == SPIRV::OpConstantI) {
2250 const unsigned LayoutVal = MILayout->getOperand(2).getImm();
2251 if (LayoutVal ==
2252 static_cast<unsigned>(SPIRV::CooperativeMatrixLayout::PackedINTEL)) {
2253 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2254 report_fatal_error("PackedINTEL layout require the following SPIR-V "
2255 "extension: SPV_INTEL_joint_matrix",
2256 false);
2257 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2258 Reqs.addCapability(SPIRV::Capability::PackedCooperativeMatrixINTEL);
2259 }
2260 }
2261
2262 // Nothing to do.
2263 if (Op == SPIRV::OpCooperativeMatrixLoadKHR ||
2264 Op == SPIRV::OpCooperativeMatrixStoreKHR)
2265 break;
2266
2267 std::string InstName;
2268 switch (Op) {
2269 case SPIRV::OpCooperativeMatrixPrefetchINTEL:
2270 InstName = "OpCooperativeMatrixPrefetchINTEL";
2271 break;
2272 case SPIRV::OpCooperativeMatrixLoadCheckedINTEL:
2273 InstName = "OpCooperativeMatrixLoadCheckedINTEL";
2274 break;
2275 case SPIRV::OpCooperativeMatrixStoreCheckedINTEL:
2276 InstName = "OpCooperativeMatrixStoreCheckedINTEL";
2277 break;
2278 }
2279
2280 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix)) {
2281 const std::string ErrorMsg =
2282 InstName + " instruction requires the "
2283 "following SPIR-V extension: SPV_INTEL_joint_matrix";
2284 report_fatal_error(ErrorMsg.c_str(), false);
2285 }
2286 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2287 if (Op == SPIRV::OpCooperativeMatrixPrefetchINTEL) {
2288 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixPrefetchINTEL);
2289 break;
2290 }
2291 Reqs.addCapability(
2292 SPIRV::Capability::CooperativeMatrixCheckedInstructionsINTEL);
2293 break;
2294 }
2295 case SPIRV::OpCooperativeMatrixConstructCheckedINTEL:
2296 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2297 report_fatal_error("OpCooperativeMatrixConstructCheckedINTEL "
2298 "instructions require the following SPIR-V extension: "
2299 "SPV_INTEL_joint_matrix",
2300 false);
2301 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2302 Reqs.addCapability(
2303 SPIRV::Capability::CooperativeMatrixCheckedInstructionsINTEL);
2304 break;
2305 case SPIRV::OpReadPipeBlockingALTERA:
2306 case SPIRV::OpWritePipeBlockingALTERA:
2307 if (ST.canUseExtension(SPIRV::Extension::SPV_ALTERA_blocking_pipes)) {
2308 Reqs.addExtension(SPIRV::Extension::SPV_ALTERA_blocking_pipes);
2309 Reqs.addCapability(SPIRV::Capability::BlockingPipesALTERA);
2310 }
2311 break;
2312 case SPIRV::OpCooperativeMatrixGetElementCoordINTEL:
2313 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2314 report_fatal_error("OpCooperativeMatrixGetElementCoordINTEL requires the "
2315 "following SPIR-V extension: SPV_INTEL_joint_matrix",
2316 false);
2317 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2318 Reqs.addCapability(
2319 SPIRV::Capability::CooperativeMatrixInvocationInstructionsINTEL);
2320 break;
2321 case SPIRV::OpConvertHandleToImageINTEL:
2322 case SPIRV::OpConvertHandleToSamplerINTEL:
2323 case SPIRV::OpConvertHandleToSampledImageINTEL: {
2324 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bindless_images))
2325 report_fatal_error("OpConvertHandleTo[Image/Sampler/SampledImage]INTEL "
2326 "instructions require the following SPIR-V extension: "
2327 "SPV_INTEL_bindless_images",
2328 false);
2329 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
2330 SPIRV::AddressingModel::AddressingModel AddrModel = MAI.Addr;
2331 SPIRVTypeInst TyDef = GR->getSPIRVTypeForVReg(MI.getOperand(1).getReg());
2332 if (Op == SPIRV::OpConvertHandleToImageINTEL &&
2333 TyDef->getOpcode() != SPIRV::OpTypeImage) {
2334 report_fatal_error("Incorrect return type for the instruction "
2335 "OpConvertHandleToImageINTEL",
2336 false);
2337 } else if (Op == SPIRV::OpConvertHandleToSamplerINTEL &&
2338 TyDef->getOpcode() != SPIRV::OpTypeSampler) {
2339 report_fatal_error("Incorrect return type for the instruction "
2340 "OpConvertHandleToSamplerINTEL",
2341 false);
2342 } else if (Op == SPIRV::OpConvertHandleToSampledImageINTEL &&
2343 TyDef->getOpcode() != SPIRV::OpTypeSampledImage) {
2344 report_fatal_error("Incorrect return type for the instruction "
2345 "OpConvertHandleToSampledImageINTEL",
2346 false);
2347 }
2348 SPIRVTypeInst SpvTy = GR->getSPIRVTypeForVReg(MI.getOperand(2).getReg());
2349 unsigned Bitwidth = GR->getScalarOrVectorBitWidth(SpvTy);
2350 if (!(Bitwidth == 32 && AddrModel == SPIRV::AddressingModel::Physical32) &&
2351 !(Bitwidth == 64 && AddrModel == SPIRV::AddressingModel::Physical64)) {
2353 "Parameter value must be a 32-bit scalar in case of "
2354 "Physical32 addressing model or a 64-bit scalar in case of "
2355 "Physical64 addressing model",
2356 false);
2357 }
2358 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bindless_images);
2359 Reqs.addCapability(SPIRV::Capability::BindlessImagesINTEL);
2360 break;
2361 }
2362 case SPIRV::OpSubgroup2DBlockLoadINTEL:
2363 case SPIRV::OpSubgroup2DBlockLoadTransposeINTEL:
2364 case SPIRV::OpSubgroup2DBlockLoadTransformINTEL:
2365 case SPIRV::OpSubgroup2DBlockPrefetchINTEL:
2366 case SPIRV::OpSubgroup2DBlockStoreINTEL: {
2367 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_2d_block_io))
2368 report_fatal_error("OpSubgroup2DBlock[Load/LoadTranspose/LoadTransform/"
2369 "Prefetch/Store]INTEL instructions require the "
2370 "following SPIR-V extension: SPV_INTEL_2d_block_io",
2371 false);
2372 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_2d_block_io);
2373 Reqs.addCapability(SPIRV::Capability::Subgroup2DBlockIOINTEL);
2374
2375 if (Op == SPIRV::OpSubgroup2DBlockLoadTransposeINTEL) {
2376 Reqs.addCapability(SPIRV::Capability::Subgroup2DBlockTransposeINTEL);
2377 break;
2378 }
2379 if (Op == SPIRV::OpSubgroup2DBlockLoadTransformINTEL) {
2380 Reqs.addCapability(SPIRV::Capability::Subgroup2DBlockTransformINTEL);
2381 break;
2382 }
2383 break;
2384 }
2385 case SPIRV::OpKill: {
2386 Reqs.addCapability(SPIRV::Capability::Shader);
2387 } break;
2388 case SPIRV::OpDemoteToHelperInvocation:
2389 Reqs.addCapability(SPIRV::Capability::DemoteToHelperInvocation);
2390
2391 if (ST.canUseExtension(
2392 SPIRV::Extension::SPV_EXT_demote_to_helper_invocation)) {
2393 if (!ST.isAtLeastSPIRVVer(llvm::VersionTuple(1, 6)))
2394 Reqs.addExtension(
2395 SPIRV::Extension::SPV_EXT_demote_to_helper_invocation);
2396 }
2397 break;
2398 case SPIRV::OpSDot:
2399 case SPIRV::OpUDot:
2400 case SPIRV::OpSUDot:
2401 case SPIRV::OpSDotAccSat:
2402 case SPIRV::OpUDotAccSat:
2403 case SPIRV::OpSUDotAccSat:
2404 AddDotProductRequirements(MI, Reqs, ST);
2405 break;
2406 case SPIRV::OpImageSampleImplicitLod:
2407 case SPIRV::OpImageFetch:
2408 Reqs.addCapability(SPIRV::Capability::Shader);
2409 addImageOperandReqs(MI, Reqs, ST, 4);
2410 break;
2411 case SPIRV::OpImageSampleExplicitLod:
2412 addImageOperandReqs(MI, Reqs, ST, 4);
2413 break;
2414 case SPIRV::OpImageSampleDrefImplicitLod:
2415 case SPIRV::OpImageSampleDrefExplicitLod:
2416 case SPIRV::OpImageDrefGather:
2417 case SPIRV::OpImageGather:
2418 Reqs.addCapability(SPIRV::Capability::Shader);
2419 addImageOperandReqs(MI, Reqs, ST, 5);
2420 break;
2421 case SPIRV::OpImageRead: {
2422 Register ImageReg = MI.getOperand(2).getReg();
2423 SPIRVTypeInst TypeDef = ST.getSPIRVGlobalRegistry()->getResultType(
2424 ImageReg, const_cast<MachineFunction *>(MI.getMF()));
2425 // OpImageRead and OpImageWrite can use Unknown Image Formats
2426 // when the Kernel capability is declared. In the OpenCL environment we are
2427 // not allowed to produce
2428 // StorageImageReadWithoutFormat/StorageImageWriteWithoutFormat, see
2429 // https://github.com/KhronosGroup/SPIRV-Headers/issues/487
2430
2431 if (isImageTypeWithUnknownFormat(TypeDef) && ST.isShader())
2432 Reqs.addCapability(SPIRV::Capability::StorageImageReadWithoutFormat);
2433 break;
2434 }
2435 case SPIRV::OpImageWrite: {
2436 Register ImageReg = MI.getOperand(0).getReg();
2437 SPIRVTypeInst TypeDef = ST.getSPIRVGlobalRegistry()->getResultType(
2438 ImageReg, const_cast<MachineFunction *>(MI.getMF()));
2439 // OpImageRead and OpImageWrite can use Unknown Image Formats
2440 // when the Kernel capability is declared. In the OpenCL environment we are
2441 // not allowed to produce
2442 // StorageImageReadWithoutFormat/StorageImageWriteWithoutFormat, see
2443 // https://github.com/KhronosGroup/SPIRV-Headers/issues/487
2444
2445 if (isImageTypeWithUnknownFormat(TypeDef) && ST.isShader())
2446 Reqs.addCapability(SPIRV::Capability::StorageImageWriteWithoutFormat);
2447 break;
2448 }
2449 case SPIRV::OpTypeStructContinuedINTEL:
2450 case SPIRV::OpConstantCompositeContinuedINTEL:
2451 case SPIRV::OpSpecConstantCompositeContinuedINTEL:
2452 case SPIRV::OpCompositeConstructContinuedINTEL: {
2453 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_long_composites))
2455 "Continued instructions require the "
2456 "following SPIR-V extension: SPV_INTEL_long_composites",
2457 false);
2458 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_long_composites);
2459 Reqs.addCapability(SPIRV::Capability::LongCompositesINTEL);
2460 break;
2461 }
2462 case SPIRV::OpArbitraryFloatEQALTERA:
2463 case SPIRV::OpArbitraryFloatGEALTERA:
2464 case SPIRV::OpArbitraryFloatGTALTERA:
2465 case SPIRV::OpArbitraryFloatLEALTERA:
2466 case SPIRV::OpArbitraryFloatLTALTERA:
2467 case SPIRV::OpArbitraryFloatCbrtALTERA:
2468 case SPIRV::OpArbitraryFloatCosALTERA:
2469 case SPIRV::OpArbitraryFloatCosPiALTERA:
2470 case SPIRV::OpArbitraryFloatExp10ALTERA:
2471 case SPIRV::OpArbitraryFloatExp2ALTERA:
2472 case SPIRV::OpArbitraryFloatExpALTERA:
2473 case SPIRV::OpArbitraryFloatExpm1ALTERA:
2474 case SPIRV::OpArbitraryFloatHypotALTERA:
2475 case SPIRV::OpArbitraryFloatLog10ALTERA:
2476 case SPIRV::OpArbitraryFloatLog1pALTERA:
2477 case SPIRV::OpArbitraryFloatLog2ALTERA:
2478 case SPIRV::OpArbitraryFloatLogALTERA:
2479 case SPIRV::OpArbitraryFloatRecipALTERA:
2480 case SPIRV::OpArbitraryFloatSinCosALTERA:
2481 case SPIRV::OpArbitraryFloatSinCosPiALTERA:
2482 case SPIRV::OpArbitraryFloatSinALTERA:
2483 case SPIRV::OpArbitraryFloatSinPiALTERA:
2484 case SPIRV::OpArbitraryFloatSqrtALTERA:
2485 case SPIRV::OpArbitraryFloatACosALTERA:
2486 case SPIRV::OpArbitraryFloatACosPiALTERA:
2487 case SPIRV::OpArbitraryFloatAddALTERA:
2488 case SPIRV::OpArbitraryFloatASinALTERA:
2489 case SPIRV::OpArbitraryFloatASinPiALTERA:
2490 case SPIRV::OpArbitraryFloatATan2ALTERA:
2491 case SPIRV::OpArbitraryFloatATanALTERA:
2492 case SPIRV::OpArbitraryFloatATanPiALTERA:
2493 case SPIRV::OpArbitraryFloatCastFromIntALTERA:
2494 case SPIRV::OpArbitraryFloatCastALTERA:
2495 case SPIRV::OpArbitraryFloatCastToIntALTERA:
2496 case SPIRV::OpArbitraryFloatDivALTERA:
2497 case SPIRV::OpArbitraryFloatMulALTERA:
2498 case SPIRV::OpArbitraryFloatPowALTERA:
2499 case SPIRV::OpArbitraryFloatPowNALTERA:
2500 case SPIRV::OpArbitraryFloatPowRALTERA:
2501 case SPIRV::OpArbitraryFloatRSqrtALTERA:
2502 case SPIRV::OpArbitraryFloatSubALTERA: {
2503 if (!ST.canUseExtension(
2504 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_floating_point))
2506 "Floating point instructions can't be translated correctly without "
2507 "enabled SPV_ALTERA_arbitrary_precision_floating_point extension!",
2508 false);
2509 Reqs.addExtension(
2510 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_floating_point);
2511 Reqs.addCapability(
2512 SPIRV::Capability::ArbitraryPrecisionFloatingPointALTERA);
2513 break;
2514 }
2515 case SPIRV::OpSubgroupMatrixMultiplyAccumulateINTEL: {
2516 if (!ST.canUseExtension(
2517 SPIRV::Extension::SPV_INTEL_subgroup_matrix_multiply_accumulate))
2519 "OpSubgroupMatrixMultiplyAccumulateINTEL instruction requires the "
2520 "following SPIR-V "
2521 "extension: SPV_INTEL_subgroup_matrix_multiply_accumulate",
2522 false);
2523 Reqs.addExtension(
2524 SPIRV::Extension::SPV_INTEL_subgroup_matrix_multiply_accumulate);
2525 Reqs.addCapability(
2526 SPIRV::Capability::SubgroupMatrixMultiplyAccumulateINTEL);
2527 break;
2528 }
2529 case SPIRV::OpBitwiseFunctionINTEL: {
2530 if (!ST.canUseExtension(
2531 SPIRV::Extension::SPV_INTEL_ternary_bitwise_function))
2533 "OpBitwiseFunctionINTEL instruction requires the following SPIR-V "
2534 "extension: SPV_INTEL_ternary_bitwise_function",
2535 false);
2536 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_ternary_bitwise_function);
2537 Reqs.addCapability(SPIRV::Capability::TernaryBitwiseFunctionINTEL);
2538 break;
2539 }
2540 case SPIRV::OpCopyMemorySized: {
2541 Reqs.addCapability(SPIRV::Capability::Addresses);
2542 // TODO: Add UntypedPointersKHR when implemented.
2543 break;
2544 }
2545 case SPIRV::OpTypeUntypedPointerKHR:
2546 Reqs.getAndAddRequirements(SPIRV::OperandCategory::StorageClassOperand,
2547 MI.getOperand(1).getImm(), ST);
2548 [[fallthrough]];
2549 case SPIRV::OpUntypedVariableKHR:
2550 case SPIRV::OpUntypedAccessChainKHR:
2551 case SPIRV::OpUntypedInBoundsAccessChainKHR:
2552 case SPIRV::OpUntypedPtrAccessChainKHR:
2553 case SPIRV::OpUntypedInBoundsPtrAccessChainKHR:
2554 case SPIRV::OpUntypedPrefetchKHR:
2555 case SPIRV::OpUntypedGroupAsyncCopyKHR: {
2556 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_untyped_pointers))
2557 report_fatal_error("Untyped pointer instructions require the following "
2558 "SPIR-V extension: SPV_KHR_untyped_pointers",
2559 false);
2560 Reqs.addExtension(SPIRV::Extension::SPV_KHR_untyped_pointers);
2561 Reqs.addCapability(SPIRV::Capability::UntypedPointersKHR);
2562 break;
2563 }
2564 case SPIRV::OpPredicatedLoadINTEL:
2565 case SPIRV::OpPredicatedStoreINTEL: {
2566 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_predicated_io))
2568 "OpPredicated[Load/Store]INTEL instructions require "
2569 "the following SPIR-V extension: SPV_INTEL_predicated_io",
2570 false);
2571 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_predicated_io);
2572 Reqs.addCapability(SPIRV::Capability::PredicatedIOINTEL);
2573 break;
2574 }
2575 case SPIRV::OpFAddS:
2576 case SPIRV::OpFSubS:
2577 case SPIRV::OpFMulS:
2578 case SPIRV::OpFDivS:
2579 case SPIRV::OpFRemS:
2580 case SPIRV::OpFMod:
2581 case SPIRV::OpFNegate:
2582 case SPIRV::OpFAddV:
2583 case SPIRV::OpFSubV:
2584 case SPIRV::OpFMulV:
2585 case SPIRV::OpFDivV:
2586 case SPIRV::OpFRemV:
2587 case SPIRV::OpFNegateV: {
2588 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
2589 SPIRVTypeInst TypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
2590 if (isVectorType(TypeDef))
2591 TypeDef = MRI.getVRegDef(TypeDef->getOperand(1).getReg());
2592 if (isBFloat16Type(TypeDef)) {
2593 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic))
2595 "Arithmetic instructions with bfloat16 arguments require the "
2596 "following SPIR-V extension: SPV_INTEL_bfloat16_arithmetic",
2597 false);
2598 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic);
2599 Reqs.addCapability(SPIRV::Capability::BFloat16ArithmeticINTEL);
2600 }
2601 break;
2602 }
2603 case SPIRV::OpOrdered:
2604 case SPIRV::OpUnordered:
2605 case SPIRV::OpFOrdEqual:
2606 case SPIRV::OpFOrdNotEqual:
2607 case SPIRV::OpFOrdLessThan:
2608 case SPIRV::OpFOrdLessThanEqual:
2609 case SPIRV::OpFOrdGreaterThan:
2610 case SPIRV::OpFOrdGreaterThanEqual:
2611 case SPIRV::OpFUnordEqual:
2612 case SPIRV::OpFUnordNotEqual:
2613 case SPIRV::OpFUnordLessThan:
2614 case SPIRV::OpFUnordLessThanEqual:
2615 case SPIRV::OpFUnordGreaterThan:
2616 case SPIRV::OpFUnordGreaterThanEqual: {
2617 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
2618 MachineInstr *OperandDef = MRI.getVRegDef(MI.getOperand(2).getReg());
2619 SPIRVTypeInst TypeDef = MRI.getVRegDef(OperandDef->getOperand(1).getReg());
2620 if (isVectorType(TypeDef))
2621 TypeDef = MRI.getVRegDef(TypeDef->getOperand(1).getReg());
2622 if (isBFloat16Type(TypeDef)) {
2623 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic))
2625 "Relational instructions with bfloat16 arguments require the "
2626 "following SPIR-V extension: SPV_INTEL_bfloat16_arithmetic",
2627 false);
2628 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic);
2629 Reqs.addCapability(SPIRV::Capability::BFloat16ArithmeticINTEL);
2630 }
2631 break;
2632 }
2633 case SPIRV::OpDPdxCoarse:
2634 case SPIRV::OpDPdyCoarse:
2635 case SPIRV::OpDPdxFine:
2636 case SPIRV::OpDPdyFine: {
2637 Reqs.addCapability(SPIRV::Capability::DerivativeControl);
2638 break;
2639 }
2640 case SPIRV::OpLoopControlINTEL: {
2641 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_unstructured_loop_controls);
2642 Reqs.addCapability(SPIRV::Capability::UnstructuredLoopControlsINTEL);
2643 break;
2644 }
2645
2646 default:
2647 break;
2648 }
2649
2650 // If we require capability Shader, then we can remove the requirement for
2651 // the BitInstructions capability, since Shader is a superset capability
2652 // of BitInstructions.
2653 Reqs.removeCapabilityIf(SPIRV::Capability::BitInstructions,
2654 SPIRV::Capability::Shader);
2655}
2656
2658 MachineModuleInfo *MMI, const SPIRVSubtarget &ST) {
2659 // Collect requirements for existing instructions.
2660 for (const Function &F : M) {
2662 if (!MF)
2663 continue;
2664 for (const MachineBasicBlock &MBB : *MF)
2665 for (const MachineInstr &MI : MBB)
2666 addInstrRequirements(MI, MAI, ST);
2667 }
2668 // Collect requirements for OpExecutionMode instructions.
2669 auto Node = M.getNamedMetadata("spirv.ExecutionMode");
2670 if (Node) {
2671 bool RequireFloatControls = false, RequireIntelFloatControls2 = false,
2672 RequireKHRFloatControls2 = false,
2673 VerLower14 = !ST.isAtLeastSPIRVVer(VersionTuple(1, 4));
2674 bool HasIntelFloatControls2 =
2675 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_float_controls2);
2676 bool HasKHRFloatControls2 =
2677 ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2);
2678 for (unsigned i = 0; i < Node->getNumOperands(); i++) {
2679 MDNode *MDN = cast<MDNode>(Node->getOperand(i));
2680 const MDOperand &MDOp = MDN->getOperand(1);
2681 if (auto *CMeta = dyn_cast<ConstantAsMetadata>(MDOp)) {
2682 Constant *C = CMeta->getValue();
2683 if (ConstantInt *Const = dyn_cast<ConstantInt>(C)) {
2684 auto EM = Const->getZExtValue();
2685 // SPV_KHR_float_controls is not available until v1.4:
2686 // add SPV_KHR_float_controls if the version is too low
2687 switch (EM) {
2688 case SPIRV::ExecutionMode::DenormPreserve:
2689 case SPIRV::ExecutionMode::DenormFlushToZero:
2690 case SPIRV::ExecutionMode::RoundingModeRTE:
2691 case SPIRV::ExecutionMode::RoundingModeRTZ:
2692 RequireFloatControls = VerLower14;
2694 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2695 break;
2696 case SPIRV::ExecutionMode::RoundingModeRTPINTEL:
2697 case SPIRV::ExecutionMode::RoundingModeRTNINTEL:
2698 case SPIRV::ExecutionMode::FloatingPointModeALTINTEL:
2699 case SPIRV::ExecutionMode::FloatingPointModeIEEEINTEL:
2700 if (HasIntelFloatControls2) {
2701 RequireIntelFloatControls2 = true;
2703 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2704 }
2705 break;
2706 case SPIRV::ExecutionMode::FPFastMathDefault: {
2707 if (HasKHRFloatControls2) {
2708 RequireKHRFloatControls2 = true;
2710 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2711 }
2712 break;
2713 }
2714 case SPIRV::ExecutionMode::ContractionOff:
2715 case SPIRV::ExecutionMode::SignedZeroInfNanPreserve:
2716 if (HasKHRFloatControls2) {
2717 RequireKHRFloatControls2 = true;
2719 SPIRV::OperandCategory::ExecutionModeOperand,
2720 SPIRV::ExecutionMode::FPFastMathDefault, ST);
2721 } else {
2723 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2724 }
2725 break;
2726 default:
2728 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2729 }
2730 }
2731 }
2732 }
2733 if (RequireFloatControls &&
2734 ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls))
2735 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls);
2736 if (RequireIntelFloatControls2)
2737 MAI.Reqs.addExtension(SPIRV::Extension::SPV_INTEL_float_controls2);
2738 if (RequireKHRFloatControls2)
2739 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls2);
2740 }
2741 for (const Function &F : M) {
2742 if (F.isDeclaration())
2743 continue;
2744 if (F.getMetadata("reqd_work_group_size"))
2746 SPIRV::OperandCategory::ExecutionModeOperand,
2747 SPIRV::ExecutionMode::LocalSize, ST);
2748 if (F.getFnAttribute("hlsl.numthreads").isValid()) {
2750 SPIRV::OperandCategory::ExecutionModeOperand,
2751 SPIRV::ExecutionMode::LocalSize, ST);
2752 }
2753 if (F.getFnAttribute("enable-maximal-reconvergence").getValueAsBool()) {
2754 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_maximal_reconvergence);
2755 }
2756 if (F.getMetadata("work_group_size_hint"))
2758 SPIRV::OperandCategory::ExecutionModeOperand,
2759 SPIRV::ExecutionMode::LocalSizeHint, ST);
2760 if (F.getMetadata("intel_reqd_sub_group_size") ||
2761 F.getMetadata("reqd_sub_group_size"))
2763 SPIRV::OperandCategory::ExecutionModeOperand,
2764 SPIRV::ExecutionMode::SubgroupSize, ST);
2765 if (F.getMetadata("max_work_group_size"))
2767 SPIRV::OperandCategory::ExecutionModeOperand,
2768 SPIRV::ExecutionMode::MaxWorkgroupSizeINTEL, ST);
2769 if (F.getMetadata("vec_type_hint"))
2771 SPIRV::OperandCategory::ExecutionModeOperand,
2772 SPIRV::ExecutionMode::VecTypeHint, ST);
2773
2774 if (F.hasOptNone()) {
2775 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_optnone)) {
2776 MAI.Reqs.addExtension(SPIRV::Extension::SPV_INTEL_optnone);
2777 MAI.Reqs.addCapability(SPIRV::Capability::OptNoneINTEL);
2778 } else if (ST.canUseExtension(SPIRV::Extension::SPV_EXT_optnone)) {
2779 MAI.Reqs.addExtension(SPIRV::Extension::SPV_EXT_optnone);
2780 MAI.Reqs.addCapability(SPIRV::Capability::OptNoneEXT);
2781 }
2782 }
2783 }
2784}
2785
2786static unsigned getFastMathFlags(const MachineInstr &I,
2787 const SPIRVSubtarget &ST) {
2788 unsigned Flags = SPIRV::FPFastMathMode::None;
2789 bool CanUseKHRFloatControls2 =
2790 ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2);
2791 if (I.getFlag(MachineInstr::MIFlag::FmNoNans))
2792 Flags |= SPIRV::FPFastMathMode::NotNaN;
2793 if (I.getFlag(MachineInstr::MIFlag::FmNoInfs))
2794 Flags |= SPIRV::FPFastMathMode::NotInf;
2795 if (I.getFlag(MachineInstr::MIFlag::FmNsz))
2796 Flags |= SPIRV::FPFastMathMode::NSZ;
2797 if (I.getFlag(MachineInstr::MIFlag::FmArcp))
2798 Flags |= SPIRV::FPFastMathMode::AllowRecip;
2799 if (I.getFlag(MachineInstr::MIFlag::FmContract) && CanUseKHRFloatControls2)
2800 Flags |= SPIRV::FPFastMathMode::AllowContract;
2801 if (I.getFlag(MachineInstr::MIFlag::FmReassoc)) {
2802 if (CanUseKHRFloatControls2)
2803 // LLVM reassoc maps to SPIRV transform, see
2804 // https://github.com/KhronosGroup/SPIRV-Registry/issues/326 for details.
2805 // Because we are enabling AllowTransform, we must enable AllowReassoc and
2806 // AllowContract too, as required by SPIRV spec. Also, we used to map
2807 // MIFlag::FmReassoc to FPFastMathMode::Fast, which now should instead by
2808 // replaced by turning all the other bits instead. Therefore, we're
2809 // enabling every bit here except None and Fast.
2810 Flags |= SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
2811 SPIRV::FPFastMathMode::NSZ | SPIRV::FPFastMathMode::AllowRecip |
2812 SPIRV::FPFastMathMode::AllowTransform |
2813 SPIRV::FPFastMathMode::AllowReassoc |
2814 SPIRV::FPFastMathMode::AllowContract;
2815 else
2816 Flags |= SPIRV::FPFastMathMode::Fast;
2817 }
2818
2819 if (CanUseKHRFloatControls2) {
2820 // Error out if SPIRV::FPFastMathMode::Fast is enabled.
2821 assert(!(Flags & SPIRV::FPFastMathMode::Fast) &&
2822 "SPIRV::FPFastMathMode::Fast is deprecated and should not be used "
2823 "anymore.");
2824
2825 // Error out if AllowTransform is enabled without AllowReassoc and
2826 // AllowContract.
2827 assert((!(Flags & SPIRV::FPFastMathMode::AllowTransform) ||
2828 ((Flags & SPIRV::FPFastMathMode::AllowReassoc &&
2829 Flags & SPIRV::FPFastMathMode::AllowContract))) &&
2830 "SPIRV::FPFastMathMode::AllowTransform requires AllowReassoc and "
2831 "AllowContract flags to be enabled as well.");
2832 }
2833
2834 return Flags;
2835}
2836
2838 if (ST.isKernel())
2839 return true;
2840 if (ST.getSPIRVVersion() < VersionTuple(1, 2))
2841 return false;
2842 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2);
2843}
2844
2846 MachineInstr &I, const SPIRVSubtarget &ST, const SPIRVInstrInfo &TII,
2848 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec) {
2849 if (TII.canUseIntegerWrapDecoration(I)) {
2850 if (I.getFlag(MachineInstr::MIFlag::NoSWrap) &&
2852 SPIRV::OperandCategory::DecorationOperand,
2853 SPIRV::Decoration::NoSignedWrap, ST, Reqs)
2854 .IsSatisfiable)
2855 buildOpDecorate(I.getOperand(0).getReg(), I, TII,
2856 SPIRV::Decoration::NoSignedWrap, {});
2857 if (I.getFlag(MachineInstr::MIFlag::NoUWrap) &&
2859 SPIRV::OperandCategory::DecorationOperand,
2860 SPIRV::Decoration::NoUnsignedWrap, ST, Reqs)
2861 .IsSatisfiable)
2862 buildOpDecorate(I.getOperand(0).getReg(), I, TII,
2863 SPIRV::Decoration::NoUnsignedWrap, {});
2864 }
2865 // In Kernel environments, FPFastMathMode on OpExtInst is valid per core
2866 // spec. For other instruction types, SPV_KHR_float_controls2 is required.
2867 bool CanUseFM =
2868 TII.canUseFastMathFlags(
2869 I, ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2)) ||
2870 (ST.isKernel() && I.getOpcode() == SPIRV::OpExtInst);
2871 if (!CanUseFM)
2872 return;
2873
2874 unsigned FMFlags = getFastMathFlags(I, ST);
2875 if (FMFlags == SPIRV::FPFastMathMode::None) {
2876 // We also need to check if any FPFastMathDefault info was set for the
2877 // types used in this instruction.
2878 if (FPFastMathDefaultInfoVec.empty())
2879 return;
2880
2881 // There are three types of instructions that can use fast math flags:
2882 // 1. Arithmetic instructions (FAdd, FMul, FSub, FDiv, FRem, etc.)
2883 // 2. Relational instructions (FCmp, FOrd, FUnord, etc.)
2884 // 3. Extended instructions (ExtInst)
2885 // For arithmetic instructions, the floating point type can be in the
2886 // result type or in the operands, but they all must be the same.
2887 // For the relational and logical instructions, the floating point type
2888 // can only be in the operands 1 and 2, not the result type. Also, the
2889 // operands must have the same type. For the extended instructions, the
2890 // floating point type can be in the result type or in the operands. It's
2891 // unclear if the operands and the result type must be the same. Let's
2892 // assume they must be. Therefore, for 1. and 2., we can check the first
2893 // operand type, and for 3. we can check the result type.
2894 assert(I.getNumOperands() >= 3 && "Expected at least 3 operands");
2895 Register ResReg = I.getOpcode() == SPIRV::OpExtInst
2896 ? I.getOperand(1).getReg()
2897 : I.getOperand(2).getReg();
2898 SPIRVTypeInst ResType = GR->getSPIRVTypeForVReg(ResReg, I.getMF());
2899 const Type *Ty = GR->getTypeForSPIRVType(ResType);
2900 Ty = Ty->isVectorTy() ? cast<VectorType>(Ty)->getElementType() : Ty;
2901
2902 // Match instruction type with the FPFastMathDefaultInfoVec.
2903 bool Emit = false;
2904 for (SPIRV::FPFastMathDefaultInfo &Elem : FPFastMathDefaultInfoVec) {
2905 if (Ty == Elem.Ty) {
2906 FMFlags = Elem.FastMathFlags;
2907 Emit = Elem.ContractionOff || Elem.SignedZeroInfNanPreserve ||
2908 Elem.FPFastMathDefault;
2909 break;
2910 }
2911 }
2912
2913 if (FMFlags == SPIRV::FPFastMathMode::None && !Emit)
2914 return;
2915 }
2916 if (isFastMathModeAvailable(ST)) {
2917 Register DstReg = I.getOperand(0).getReg();
2918 buildOpDecorate(DstReg, I, TII, SPIRV::Decoration::FPFastMathMode,
2919 {FMFlags});
2920 }
2921}
2922
2923// Walk all functions and add decorations related to MI flags.
2924static void addDecorations(const Module &M, const SPIRVInstrInfo &TII,
2925 MachineModuleInfo *MMI, const SPIRVSubtarget &ST,
2927 const SPIRVGlobalRegistry *GR) {
2928 for (const Function &F : M) {
2930 if (!MF)
2931 continue;
2932
2933 for (auto &MBB : *MF)
2934 for (auto &MI : MBB)
2935 handleMIFlagDecoration(MI, ST, TII, MAI.Reqs, GR,
2937 }
2938}
2939
2940static void addMBBNames(const Module &M, const SPIRVInstrInfo &TII,
2941 MachineModuleInfo *MMI, const SPIRVSubtarget &ST,
2943 for (const Function &F : M) {
2945 if (!MF)
2946 continue;
2947 if (MF->getFunction()
2949 .isValid())
2950 continue;
2951 MachineRegisterInfo &MRI = MF->getRegInfo();
2952 for (auto &MBB : *MF) {
2953 if (!MBB.hasName() || MBB.empty())
2954 continue;
2955 // Emit basic block names.
2957 MRI.setRegClass(Reg, &SPIRV::IDRegClass);
2958 buildOpName(Reg, MBB.getName(), *std::prev(MBB.end()), TII);
2959 MCRegister GlobalReg = MAI.getOrCreateMBBRegister(MBB);
2960 MAI.setRegisterAlias(MF, Reg, GlobalReg);
2961 }
2962 }
2963}
2964
2965// patching Instruction::PHI to SPIRV::OpPhi
2966static void patchPhis(const Module &M, SPIRVGlobalRegistry *GR,
2967 const SPIRVInstrInfo &TII, MachineModuleInfo *MMI) {
2968 for (const Function &F : M) {
2970 if (!MF)
2971 continue;
2972 for (auto &MBB : *MF) {
2973 for (MachineInstr &MI : MBB.phis()) {
2974 MI.setDesc(TII.get(SPIRV::OpPhi));
2975 Register ResTypeReg = GR->getSPIRVTypeID(
2976 GR->getSPIRVTypeForVReg(MI.getOperand(0).getReg(), MF));
2977 MI.insert(MI.operands_begin() + 1,
2978 {MachineOperand::CreateReg(ResTypeReg, false)});
2979 }
2980 }
2981
2982 MF->getProperties().setNoPHIs();
2983 }
2984}
2985
2987 const Module &M, SPIRV::ModuleAnalysisInfo &MAI, const Function *F) {
2988 auto it = MAI.FPFastMathDefaultInfoMap.find(F);
2989 if (it != MAI.FPFastMathDefaultInfoMap.end())
2990 return it->second;
2991
2992 // If the map does not contain the entry, create a new one. Initialize it to
2993 // contain all 3 elements sorted by bit width of target type: {half, float,
2994 // double}.
2995 SPIRV::FPFastMathDefaultInfoVector FPFastMathDefaultInfoVec;
2996 FPFastMathDefaultInfoVec.emplace_back(Type::getHalfTy(M.getContext()),
2997 SPIRV::FPFastMathMode::None);
2998 FPFastMathDefaultInfoVec.emplace_back(Type::getFloatTy(M.getContext()),
2999 SPIRV::FPFastMathMode::None);
3000 FPFastMathDefaultInfoVec.emplace_back(Type::getDoubleTy(M.getContext()),
3001 SPIRV::FPFastMathMode::None);
3002 return MAI.FPFastMathDefaultInfoMap[F] = std::move(FPFastMathDefaultInfoVec);
3003}
3004
3006 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec,
3007 const Type *Ty) {
3008 size_t BitWidth = Ty->getScalarSizeInBits();
3009 int Index =
3011 BitWidth);
3012 assert(Index >= 0 && Index < 3 &&
3013 "Expected FPFastMathDefaultInfo for half, float, or double");
3014 assert(FPFastMathDefaultInfoVec.size() == 3 &&
3015 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3016 return FPFastMathDefaultInfoVec[Index];
3017}
3018
3021 const SPIRVSubtarget &ST) {
3022 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
3023 return;
3024
3025 // Store the FPFastMathDefaultInfo in the FPFastMathDefaultInfoMap.
3026 // We need the entry point (function) as the key, and the target
3027 // type and flags as the value.
3028 // We also need to check ContractionOff and SignedZeroInfNanPreserve
3029 // execution modes, as they are now deprecated and must be replaced
3030 // with FPFastMathDefaultInfo.
3031 auto Node = M.getNamedMetadata("spirv.ExecutionMode");
3032 if (!Node)
3033 return;
3034
3035 for (unsigned i = 0; i < Node->getNumOperands(); i++) {
3036 MDNode *MDN = cast<MDNode>(Node->getOperand(i));
3037 assert(MDN->getNumOperands() >= 2 && "Expected at least 2 operands");
3038 const Function *F = cast<Function>(
3039 cast<ConstantAsMetadata>(MDN->getOperand(0))->getValue());
3040 const auto EM =
3042 cast<ConstantAsMetadata>(MDN->getOperand(1))->getValue())
3043 ->getZExtValue();
3044 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
3045 assert(MDN->getNumOperands() == 4 &&
3046 "Expected 4 operands for FPFastMathDefault");
3047
3048 const Type *T = cast<ValueAsMetadata>(MDN->getOperand(2))->getType();
3049 unsigned Flags =
3051 cast<ConstantAsMetadata>(MDN->getOperand(3))->getValue())
3052 ->getZExtValue();
3053 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3056 getFPFastMathDefaultInfo(FPFastMathDefaultInfoVec, T);
3057 Info.FastMathFlags = Flags;
3058 Info.FPFastMathDefault = true;
3059 } else if (EM == SPIRV::ExecutionMode::ContractionOff) {
3060 assert(MDN->getNumOperands() == 2 &&
3061 "Expected no operands for ContractionOff");
3062
3063 // We need to save this info for every possible FP type, i.e. {half,
3064 // float, double, fp128}.
3065 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3067 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
3068 Info.ContractionOff = true;
3069 }
3070 } else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
3071 assert(MDN->getNumOperands() == 3 &&
3072 "Expected 1 operand for SignedZeroInfNanPreserve");
3073 unsigned TargetWidth =
3075 cast<ConstantAsMetadata>(MDN->getOperand(2))->getValue())
3076 ->getZExtValue();
3077 // We need to save this info only for the FP type with TargetWidth.
3078 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3082 assert(Index >= 0 && Index < 3 &&
3083 "Expected FPFastMathDefaultInfo for half, float, or double");
3084 assert(FPFastMathDefaultInfoVec.size() == 3 &&
3085 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3086 FPFastMathDefaultInfoVec[Index].SignedZeroInfNanPreserve = true;
3087 }
3088 }
3089}
3090
3095
3097 SPIRVTargetMachine &TM =
3099 ST = TM.getSubtargetImpl();
3100 GR = ST->getSPIRVGlobalRegistry();
3101 TII = ST->getInstrInfo();
3102
3104
3105 setBaseInfo(M);
3106
3107 patchPhis(M, GR, *TII, MMI);
3108
3109 addMBBNames(M, *TII, MMI, *ST, MAI);
3111 addDecorations(M, *TII, MMI, *ST, MAI, GR);
3112
3113 collectReqs(M, MAI, MMI, *ST);
3114
3115 // Process type/const/global var/func decl instructions, number their
3116 // destination registers from 0 to N, collect Extensions and Capabilities.
3117 collectDeclarations(M);
3118
3119 // Number rest of registers from N+1 onwards.
3120 numberRegistersGlobally(M);
3121
3122 // Collect OpName, OpEntryPoint, OpDecorate etc, process other instructions.
3123 processOtherInstrs(M);
3124
3125 // If there are no entry points, we need the Linkage capability.
3126 if (MAI.MS[SPIRV::MB_EntryPoints].empty())
3127 MAI.Reqs.addCapability(SPIRV::Capability::Linkage);
3128
3129 // Set maximum ID used.
3130 GR->setBound(MAI.MaxID);
3131
3132 return false;
3133}
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 cl::opt< bool > SPVDumpDeps("spv-dump-deps", cl::desc("Dump MIR with SPIR-V dependencies info"), cl::Optional, cl::init(false))
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 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:261
This is the shared class of boolean and integer constants.
Definition Constants.h:87
This is an important base class in LLVM.
Definition Constant.h:43
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:1069
const MDOperand & getOperand(unsigned I) const
Definition Metadata.h:1426
unsigned getNumOperands() const
Return number of MDNode operands.
Definition Metadata.h:1432
Tracking metadata reference owned by Metadata.
Definition Metadata.h:891
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:288
static LLVM_ABI Type * getDoubleTy(LLVMContext &C)
Definition Type.cpp:287
static LLVM_ABI Type * getFloatTy(LLVMContext &C)
Definition Type.cpp:286
static LLVM_ABI Type * getHalfTy(LLVMContext &C)
Definition Type.cpp:284
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:668
This is an optimization pass for GlobalISel generic memory operations.
void stable_sort(R &&Range)
Definition STLExtras.h:2116
std::string getStringImm(const MachineInstr &MI, unsigned StartIndex)
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1739
hash_code hash_value(const FixedPointSemantics &Val)
ExtensionList getSymbolicOperandExtensions(SPIRV::OperandCategory::OperandCategory Category, uint32_t Value)
CapabilityList getSymbolicOperandCapabilities(SPIRV::OperandCategory::OperandCategory Category, uint32_t Value)
SmallVector< SPIRV::Extension::Extension, 8 > ExtensionList
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
SmallVector< size_t > InstrSignature
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:2200
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:1947
SmallVector< SPIRV::Capability::Capability, 8 > CapabilityList
std::set< InstrSignature > InstrTraces
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition Hashing.h:305
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