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