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