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