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