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