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 // Selection order can place a scope/list ahead of a domain/scope it
758 // references. The dependency meanwhile is domain -> scope -> list, so sort
759 // the def before its uses.
760 auto AliasingTier = [](const MachineInstr *MI) {
761 switch (MI->getOpcode()) {
762 case SPIRV::OpAliasDomainDeclINTEL:
763 return 0;
764 case SPIRV::OpAliasScopeDeclINTEL:
765 return 1;
766 case SPIRV::OpAliasScopeListDeclINTEL:
767 return 2;
768 default:
769 llvm_unreachable("unexpected aliasing instruction");
770 }
771 };
773 [&](const MachineInstr *LHS, const MachineInstr *RHS) {
774 return AliasingTier(LHS) < AliasingTier(RHS);
775 });
776}
777
778// Number registers in all functions globally from 0 onwards and store
779// the result in global register alias table. Some registers are already
780// numbered.
781void SPIRVModuleAnalysis::numberRegistersGlobally(const Module &M) {
782 for (const Function &F : M) {
783 if (F.isDeclaration())
784 continue;
785 MachineFunction *MF = MMI->getMachineFunction(F);
786 assert(MF);
787 for (MachineBasicBlock &MBB : *MF) {
788 for (MachineInstr &MI : MBB) {
789 for (MachineOperand &Op : MI.operands()) {
790 if (!Op.isReg())
791 continue;
792 Register Reg = Op.getReg();
793 if (MAI.hasRegisterAlias(MF, Reg))
794 continue;
795 MCRegister NewReg = MAI.getNextIDRegister();
796 MAI.setRegisterAlias(MF, Reg, NewReg);
797 }
798 if (MI.getOpcode() != SPIRV::OpExtInst)
799 continue;
800 auto Set = MI.getOperand(2).getImm();
801 auto [It, Inserted] = MAI.ExtInstSetMap.try_emplace(Set);
802 if (Inserted)
803 It->second = MAI.getNextIDRegister();
804 }
805 }
806 }
807}
808
809// RequirementHandler implementations.
811 SPIRV::OperandCategory::OperandCategory Category, uint32_t i,
812 const SPIRVSubtarget &ST) {
813 addRequirements(getSymbolicOperandRequirements(Category, i, ST, *this));
814}
815
816void SPIRV::RequirementHandler::recursiveAddCapabilities(
817 const CapabilityList &ToPrune) {
818 for (const auto &Cap : ToPrune) {
819 AllCaps.insert(Cap);
820 CapabilityList ImplicitDecls =
821 getSymbolicOperandCapabilities(OperandCategory::CapabilityOperand, Cap);
822 recursiveAddCapabilities(ImplicitDecls);
823 }
824}
825
827 for (const auto &Cap : ToAdd) {
828 bool IsNewlyInserted = AllCaps.insert(Cap).second;
829 if (!IsNewlyInserted) // Don't re-add if it's already been declared.
830 continue;
831 CapabilityList ImplicitDecls =
832 getSymbolicOperandCapabilities(OperandCategory::CapabilityOperand, Cap);
833 recursiveAddCapabilities(ImplicitDecls);
834 MinimalCaps.push_back(Cap);
835 }
836}
837
839 const SPIRV::Requirements &Req) {
840 if (!Req.IsSatisfiable)
841 report_fatal_error("Adding SPIR-V requirements this target can't satisfy.");
842
843 if (Req.Cap.has_value())
844 addCapabilities({Req.Cap.value()});
845
846 addExtensions(Req.Exts);
847
848 if (!Req.MinVer.empty()) {
849 if (!MaxVersion.empty() && Req.MinVer > MaxVersion) {
850 LLVM_DEBUG(dbgs() << "Conflicting version requirements: >= " << Req.MinVer
851 << " and <= " << MaxVersion << "\n");
852 report_fatal_error("Adding SPIR-V requirements that can't be satisfied.");
853 }
854
855 if (MinVersion.empty() || Req.MinVer > MinVersion)
856 MinVersion = Req.MinVer;
857 }
858
859 if (!Req.MaxVer.empty()) {
860 if (!MinVersion.empty() && Req.MaxVer < MinVersion) {
861 LLVM_DEBUG(dbgs() << "Conflicting version requirements: <= " << Req.MaxVer
862 << " and >= " << MinVersion << "\n");
863 report_fatal_error("Adding SPIR-V requirements that can't be satisfied.");
864 }
865
866 if (MaxVersion.empty() || Req.MaxVer < MaxVersion)
867 MaxVersion = Req.MaxVer;
868 }
869}
870
872 const SPIRVSubtarget &ST) const {
873 // Report as many errors as possible before aborting the compilation.
874 bool IsSatisfiable = true;
875 auto TargetVer = ST.getSPIRVVersion();
876
877 if (!MaxVersion.empty() && !TargetVer.empty() && MaxVersion < TargetVer) {
879 dbgs() << "Target SPIR-V version too high for required features\n"
880 << "Required max version: " << MaxVersion << " target version "
881 << TargetVer << "\n");
882 IsSatisfiable = false;
883 }
884
885 if (!MinVersion.empty() && !TargetVer.empty() && MinVersion > TargetVer) {
886 LLVM_DEBUG(dbgs() << "Target SPIR-V version too low for required features\n"
887 << "Required min version: " << MinVersion
888 << " target version " << TargetVer << "\n");
889 IsSatisfiable = false;
890 }
891
892 if (!MinVersion.empty() && !MaxVersion.empty() && MinVersion > MaxVersion) {
894 dbgs()
895 << "Version is too low for some features and too high for others.\n"
896 << "Required SPIR-V min version: " << MinVersion
897 << " required SPIR-V max version " << MaxVersion << "\n");
898 IsSatisfiable = false;
899 }
900
901 AvoidCapabilitiesSet AvoidCaps;
902 if (!ST.isShader())
903 AvoidCaps.S.insert(SPIRV::Capability::Shader);
904 else
905 AvoidCaps.S.insert(SPIRV::Capability::Kernel);
906
907 for (auto Cap : MinimalCaps) {
908 if (AvailableCaps.contains(Cap) && !AvoidCaps.S.contains(Cap))
909 continue;
910 LLVM_DEBUG(dbgs() << "Capability not supported: "
912 OperandCategory::CapabilityOperand, Cap)
913 << "\n");
914 IsSatisfiable = false;
915 }
916
917 for (auto Ext : AllExtensions) {
918 if (ST.canUseExtension(Ext))
919 continue;
920 LLVM_DEBUG(dbgs() << "Extension not supported: "
922 OperandCategory::ExtensionOperand, Ext)
923 << "\n");
924 IsSatisfiable = false;
925 }
926
927 if (!IsSatisfiable)
928 report_fatal_error("Unable to meet SPIR-V requirements for this target.");
929}
930
931// Add the given capabilities and all their implicitly defined capabilities too.
933 for (const auto Cap : ToAdd)
934 if (AvailableCaps.insert(Cap).second)
935 addAvailableCaps(getSymbolicOperandCapabilities(
936 SPIRV::OperandCategory::CapabilityOperand, Cap));
937}
938
940 const Capability::Capability ToRemove,
941 const Capability::Capability IfPresent) {
942 if (AllCaps.contains(IfPresent)) {
943 AllCaps.erase(ToRemove);
944 llvm::erase(MinimalCaps, ToRemove);
945 }
946}
947
948namespace llvm {
949namespace SPIRV {
950void RequirementHandler::initAvailableCapabilities(const SPIRVSubtarget &ST) {
951 // Provided by both all supported Vulkan versions and OpenCl.
952 addAvailableCaps({Capability::Shader, Capability::Linkage, Capability::Int8,
953 Capability::Int16});
954
955 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 3)))
956 addAvailableCaps({Capability::GroupNonUniform,
957 Capability::GroupNonUniformVote,
958 Capability::GroupNonUniformArithmetic,
959 Capability::GroupNonUniformBallot,
960 Capability::GroupNonUniformClustered,
961 Capability::GroupNonUniformShuffle,
962 Capability::GroupNonUniformShuffleRelative,
963 Capability::GroupNonUniformQuad});
964
965 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 6)))
966 addAvailableCaps({Capability::DotProduct, Capability::DotProductInputAll,
967 Capability::DotProductInput4x8Bit,
968 Capability::DotProductInput4x8BitPacked,
969 Capability::DemoteToHelperInvocation});
970
971 // Add capabilities enabled by extensions.
972 for (auto Extension : ST.getAllAvailableExtensions()) {
973 CapabilityList EnabledCapabilities =
975 addAvailableCaps(EnabledCapabilities);
976 }
977
978 if (!ST.isShader()) {
979 initAvailableCapabilitiesForOpenCL(ST);
980 return;
981 }
982
983 if (ST.isShader()) {
984 initAvailableCapabilitiesForVulkan(ST);
985 return;
986 }
987
988 report_fatal_error("Unimplemented environment for SPIR-V generation.");
989}
990
991void RequirementHandler::initAvailableCapabilitiesForOpenCL(
992 const SPIRVSubtarget &ST) {
993 // Add the min requirements for different OpenCL and SPIR-V versions.
994 addAvailableCaps({Capability::Addresses, Capability::Float16Buffer,
995 Capability::Kernel, Capability::Vector16,
996 Capability::Groups, Capability::GenericPointer,
997 Capability::StorageImageWriteWithoutFormat,
998 Capability::StorageImageReadWithoutFormat});
999 if (ST.hasOpenCLFullProfile())
1000 addAvailableCaps({Capability::Int64, Capability::Int64Atomics});
1001 if (ST.hasOpenCLImageSupport()) {
1002 addAvailableCaps({Capability::ImageBasic, Capability::LiteralSampler,
1003 Capability::Image1D, Capability::SampledBuffer,
1004 Capability::ImageBuffer});
1005 if (ST.isAtLeastOpenCLVer(VersionTuple(2, 0)))
1006 addAvailableCaps({Capability::ImageReadWrite});
1007 }
1008 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 1)) &&
1009 ST.isAtLeastOpenCLVer(VersionTuple(2, 2)))
1010 addAvailableCaps({Capability::SubgroupDispatch, Capability::PipeStorage});
1011 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 4)))
1012 addAvailableCaps({Capability::DenormPreserve, Capability::DenormFlushToZero,
1013 Capability::SignedZeroInfNanPreserve,
1014 Capability::RoundingModeRTE,
1015 Capability::RoundingModeRTZ});
1016 // TODO: verify if this needs some checks.
1017 addAvailableCaps({Capability::Float16, Capability::Float64});
1018
1019 // TODO: add OpenCL extensions.
1020}
1021
1022void RequirementHandler::initAvailableCapabilitiesForVulkan(
1023 const SPIRVSubtarget &ST) {
1024
1025 // Core in Vulkan 1.1 and earlier.
1026 addAvailableCaps({Capability::Int64,
1027 Capability::Float16,
1028 Capability::Float64,
1029 Capability::GroupNonUniform,
1030 Capability::Image1D,
1031 Capability::SampledBuffer,
1032 Capability::ImageBuffer,
1033 Capability::UniformBufferArrayDynamicIndexing,
1034 Capability::SampledImageArrayDynamicIndexing,
1035 Capability::StorageBufferArrayDynamicIndexing,
1036 Capability::StorageImageArrayDynamicIndexing,
1037 Capability::DerivativeControl,
1038 Capability::MinLod,
1039 Capability::ImageQuery,
1040 Capability::ImageGatherExtended,
1041 Capability::Addresses,
1042 Capability::VulkanMemoryModelKHR,
1043 Capability::StorageImageExtendedFormats,
1044 Capability::StorageImageMultisample,
1045 Capability::ImageMSArray});
1046
1047 // Became core in Vulkan 1.2
1048 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 5))) {
1050 {Capability::Int64Atomics, Capability::ShaderNonUniformEXT,
1051 Capability::RuntimeDescriptorArrayEXT,
1052 Capability::InputAttachmentArrayDynamicIndexingEXT,
1053 Capability::UniformTexelBufferArrayDynamicIndexingEXT,
1054 Capability::StorageTexelBufferArrayDynamicIndexingEXT,
1055 Capability::UniformBufferArrayNonUniformIndexingEXT,
1056 Capability::SampledImageArrayNonUniformIndexingEXT,
1057 Capability::StorageBufferArrayNonUniformIndexingEXT,
1058 Capability::StorageImageArrayNonUniformIndexingEXT,
1059 Capability::InputAttachmentArrayNonUniformIndexingEXT,
1060 Capability::UniformTexelBufferArrayNonUniformIndexingEXT,
1061 Capability::StorageTexelBufferArrayNonUniformIndexingEXT});
1062 }
1063
1064 // Became core in Vulkan 1.3
1065 if (ST.isAtLeastSPIRVVer(VersionTuple(1, 6)))
1066 addAvailableCaps({Capability::StorageImageWriteWithoutFormat,
1067 Capability::StorageImageReadWithoutFormat});
1068}
1069
1070} // namespace SPIRV
1071} // namespace llvm
1072
1073// Add the required capabilities from a decoration instruction (including
1074// BuiltIns).
1075static void addOpDecorateReqs(const MachineInstr &MI, unsigned DecIndex,
1077 const SPIRVSubtarget &ST) {
1078 int64_t DecOp = MI.getOperand(DecIndex).getImm();
1079 auto Dec = static_cast<SPIRV::Decoration::Decoration>(DecOp);
1080 Reqs.addRequirements(getSymbolicOperandRequirements(
1081 SPIRV::OperandCategory::DecorationOperand, Dec, ST, Reqs));
1082
1083 if (Dec == SPIRV::Decoration::BuiltIn) {
1084 int64_t BuiltInOp = MI.getOperand(DecIndex + 1).getImm();
1085 auto BuiltIn = static_cast<SPIRV::BuiltIn::BuiltIn>(BuiltInOp);
1086 Reqs.addRequirements(getSymbolicOperandRequirements(
1087 SPIRV::OperandCategory::BuiltInOperand, BuiltIn, ST, Reqs));
1088 } else if (Dec == SPIRV::Decoration::LinkageAttributes) {
1089 int64_t LinkageOp = MI.getOperand(MI.getNumOperands() - 1).getImm();
1090 SPIRV::LinkageType::LinkageType LnkType =
1091 static_cast<SPIRV::LinkageType::LinkageType>(LinkageOp);
1092 if (LnkType == SPIRV::LinkageType::LinkOnceODR)
1093 Reqs.addExtension(SPIRV::Extension::SPV_KHR_linkonce_odr);
1094 else if (LnkType == SPIRV::LinkageType::WeakAMD) {
1095 Reqs.addExtension(SPIRV::Extension::SPV_AMD_weak_linkage);
1096 Reqs.addCapability(SPIRV::Capability::WeakLinkageAMD);
1097 }
1098 } else if (Dec == SPIRV::Decoration::CacheControlLoadINTEL ||
1099 Dec == SPIRV::Decoration::CacheControlStoreINTEL) {
1100 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_cache_controls);
1101 } else if (Dec == SPIRV::Decoration::HostAccessINTEL) {
1102 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_global_variable_host_access);
1103 } else if (Dec == SPIRV::Decoration::InitModeINTEL ||
1104 Dec == SPIRV::Decoration::ImplementInRegisterMapINTEL) {
1105 Reqs.addExtension(
1106 SPIRV::Extension::SPV_INTEL_global_variable_fpga_decorations);
1107 } else if (Dec == SPIRV::Decoration::NonUniformEXT) {
1108 Reqs.addRequirements(SPIRV::Capability::ShaderNonUniformEXT);
1109 } else if (Dec == SPIRV::Decoration::FPMaxErrorDecorationINTEL) {
1110 Reqs.addRequirements(SPIRV::Capability::FPMaxErrorINTEL);
1111 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_fp_max_error);
1112 } else if (Dec == SPIRV::Decoration::FPFastMathMode) {
1113 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2)) {
1114 Reqs.addRequirements(SPIRV::Capability::FloatControls2);
1115 Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls2);
1116 }
1117 }
1118}
1119
1120// Add requirements for image handling.
1121static void addOpTypeImageReqs(const MachineInstr &MI,
1123 const SPIRVSubtarget &ST) {
1124 assert(MI.getNumOperands() >= 8 && "Insufficient operands for OpTypeImage");
1125 // The operand indices used here are based on the OpTypeImage layout, which
1126 // the MachineInstr follows as well.
1127 int64_t ImgFormatOp = MI.getOperand(7).getImm();
1128 auto ImgFormat = static_cast<SPIRV::ImageFormat::ImageFormat>(ImgFormatOp);
1129 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ImageFormatOperand,
1130 ImgFormat, ST);
1131
1132 bool IsArrayed = MI.getOperand(4).getImm() == 1;
1133 bool IsMultisampled = MI.getOperand(5).getImm() == 1;
1134 bool NoSampler = MI.getOperand(6).getImm() == 2;
1135 // Add dimension requirements.
1136 assert(MI.getOperand(2).isImm());
1137 switch (MI.getOperand(2).getImm()) {
1138 case SPIRV::Dim::DIM_1D:
1139 Reqs.addRequirements(NoSampler ? SPIRV::Capability::Image1D
1140 : SPIRV::Capability::Sampled1D);
1141 break;
1142 case SPIRV::Dim::DIM_2D:
1143 if (IsMultisampled && NoSampler)
1144 Reqs.addRequirements(SPIRV::Capability::StorageImageMultisample);
1145 if (IsMultisampled && IsArrayed)
1146 Reqs.addRequirements(SPIRV::Capability::ImageMSArray);
1147 break;
1148 case SPIRV::Dim::DIM_3D:
1149 break;
1150 case SPIRV::Dim::DIM_Cube:
1151 Reqs.addRequirements(SPIRV::Capability::Shader);
1152 if (IsArrayed)
1153 Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageCubeArray
1154 : SPIRV::Capability::SampledCubeArray);
1155 break;
1156 case SPIRV::Dim::DIM_Rect:
1157 Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageRect
1158 : SPIRV::Capability::SampledRect);
1159 break;
1160 case SPIRV::Dim::DIM_Buffer:
1161 Reqs.addRequirements(NoSampler ? SPIRV::Capability::ImageBuffer
1162 : SPIRV::Capability::SampledBuffer);
1163 break;
1164 case SPIRV::Dim::DIM_SubpassData:
1165 Reqs.addRequirements(SPIRV::Capability::InputAttachment);
1166 break;
1167 }
1168
1169 // Check if the sampled type is a 64-bit integer, which requires
1170 // Int64ImageEXT capability.
1171 assert(MI.getOperand(1).isReg());
1172 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1173 SPIRVTypeInst SampledTypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
1174 if (SampledTypeDef.isTypeIntN(64)) {
1175 Reqs.addCapability(SPIRV::Capability::Int64ImageEXT);
1176 Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_image_int64);
1177 }
1178
1179 // Has optional access qualifier.
1180 if (!ST.isShader()) {
1181 if (MI.getNumOperands() > 8 &&
1182 MI.getOperand(8).getImm() == SPIRV::AccessQualifier::ReadWrite)
1183 Reqs.addRequirements(SPIRV::Capability::ImageReadWrite);
1184 else
1185 Reqs.addRequirements(SPIRV::Capability::ImageBasic);
1186 }
1187}
1188
1189static bool isBFloat16Type(SPIRVTypeInst TypeDef) {
1190 return TypeDef && TypeDef->getNumOperands() == 3 &&
1191 TypeDef->getOpcode() == SPIRV::OpTypeFloat &&
1192 TypeDef->getOperand(1).getImm() == 16 &&
1193 TypeDef->getOperand(2).getImm() == SPIRV::FPEncoding::BFloat16KHR;
1194}
1195
1196// Add requirements for handling atomic float instructions
1197#define ATOM_FLT_REQ_EXT_MSG(ExtName) \
1198 "The atomic float instruction requires the following SPIR-V " \
1199 "extension: SPV_EXT_shader_atomic_float" ExtName
1200static void AddAtomicVectorFloatRequirements(const MachineInstr &MI,
1202 const SPIRVSubtarget &ST) {
1203 SPIRVTypeInst VecTypeDef =
1204 MI.getMF()->getRegInfo().getVRegDef(MI.getOperand(1).getReg());
1205
1206 const unsigned Rank = VecTypeDef->getOperand(2).getImm();
1207 if (Rank != 2 && Rank != 4)
1208 reportFatalUsageError("Result type of an atomic vector float instruction "
1209 "must be a 2-component or 4 component vector");
1210
1211 SPIRVTypeInst EltTypeDef =
1212 MI.getMF()->getRegInfo().getVRegDef(VecTypeDef->getOperand(1).getReg());
1213
1214 if (EltTypeDef->getOpcode() != SPIRV::OpTypeFloat ||
1215 EltTypeDef->getOperand(1).getImm() != 16)
1217 "The element type for the result type of an atomic vector float "
1218 "instruction must be a 16-bit floating-point scalar");
1219
1220 // The extension is defined for fp16, but the AMD target lets a bf16 vector
1221 // use the same instruction so it can lower to a packed bf16 atomic.
1222 if (isBFloat16Type(EltTypeDef) &&
1223 ST.getTargetTriple().getVendor() != Triple::AMD)
1225 "The element type for the result type of an atomic vector float "
1226 "instruction cannot be a bfloat16 scalar");
1227 if (!ST.canUseExtension(SPIRV::Extension::SPV_NV_shader_atomic_fp16_vector))
1229 "The atomic float16 vector instruction requires the following SPIR-V "
1230 "extension: SPV_NV_shader_atomic_fp16_vector");
1231
1232 Reqs.addExtension(SPIRV::Extension::SPV_NV_shader_atomic_fp16_vector);
1233 Reqs.addCapability(SPIRV::Capability::AtomicFloat16VectorNV);
1234}
1235
1236static void AddAtomicFloatRequirements(const MachineInstr &MI,
1238 const SPIRVSubtarget &ST) {
1239 assert(MI.getOperand(1).isReg() &&
1240 "Expect register operand in atomic float instruction");
1241 Register TypeReg = MI.getOperand(1).getReg();
1242 SPIRVTypeInst TypeDef = MI.getMF()->getRegInfo().getVRegDef(TypeReg);
1243
1244 if (TypeDef->getOpcode() == SPIRV::OpTypeVector)
1245 return AddAtomicVectorFloatRequirements(MI, Reqs, ST);
1246
1247 if (TypeDef->getOpcode() != SPIRV::OpTypeFloat)
1248 report_fatal_error("Result type of an atomic float instruction must be a "
1249 "floating-point type scalar");
1250
1251 unsigned BitWidth = TypeDef->getOperand(1).getImm();
1252 unsigned Op = MI.getOpcode();
1253 if (Op == SPIRV::OpAtomicFAddEXT) {
1254 if (!ST.canUseExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_add))
1256 Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_add);
1257 switch (BitWidth) {
1258 case 16:
1259 if (isBFloat16Type(TypeDef)) {
1260 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics))
1262 "The atomic bfloat16 instruction requires the following SPIR-V "
1263 "extension: SPV_INTEL_16bit_atomics",
1264 false);
1265 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics);
1266 Reqs.addCapability(SPIRV::Capability::AtomicBFloat16AddINTEL);
1267 } else {
1268 if (!ST.canUseExtension(
1269 SPIRV::Extension::SPV_EXT_shader_atomic_float16_add))
1270 report_fatal_error(ATOM_FLT_REQ_EXT_MSG("16_add"), false);
1271 Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float16_add);
1272 Reqs.addCapability(SPIRV::Capability::AtomicFloat16AddEXT);
1273 }
1274 break;
1275 case 32:
1276 Reqs.addCapability(SPIRV::Capability::AtomicFloat32AddEXT);
1277 break;
1278 case 64:
1279 Reqs.addCapability(SPIRV::Capability::AtomicFloat64AddEXT);
1280 break;
1281 default:
1283 "Unexpected floating-point type width in atomic float instruction");
1284 }
1285 } else {
1286 if (!ST.canUseExtension(
1287 SPIRV::Extension::SPV_EXT_shader_atomic_float_min_max))
1288 report_fatal_error(ATOM_FLT_REQ_EXT_MSG("_min_max"), false);
1289 Reqs.addExtension(SPIRV::Extension::SPV_EXT_shader_atomic_float_min_max);
1290 switch (BitWidth) {
1291 case 16:
1292 if (isBFloat16Type(TypeDef)) {
1293 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics))
1295 "The atomic bfloat16 instruction requires the following SPIR-V "
1296 "extension: SPV_INTEL_16bit_atomics",
1297 false);
1298 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics);
1299 Reqs.addCapability(SPIRV::Capability::AtomicBFloat16MinMaxINTEL);
1300 } else {
1301 Reqs.addCapability(SPIRV::Capability::AtomicFloat16MinMaxEXT);
1302 }
1303 break;
1304 case 32:
1305 Reqs.addCapability(SPIRV::Capability::AtomicFloat32MinMaxEXT);
1306 break;
1307 case 64:
1308 Reqs.addCapability(SPIRV::Capability::AtomicFloat64MinMaxEXT);
1309 break;
1310 default:
1312 "Unexpected floating-point type width in atomic float instruction");
1313 }
1314 }
1315}
1316
1317bool isUniformTexelBuffer(MachineInstr *ImageInst) {
1318 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1319 return false;
1320 uint32_t Dim = ImageInst->getOperand(2).getImm();
1321 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1322 return Dim == SPIRV::Dim::DIM_Buffer && Sampled == 1;
1323}
1324
1325bool isStorageTexelBuffer(MachineInstr *ImageInst) {
1326 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1327 return false;
1328 uint32_t Dim = ImageInst->getOperand(2).getImm();
1329 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1330 return Dim == SPIRV::Dim::DIM_Buffer && Sampled == 2;
1331}
1332
1333bool isSampledImage(MachineInstr *ImageInst) {
1334 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1335 return false;
1336 uint32_t Dim = ImageInst->getOperand(2).getImm();
1337 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1338 return Dim != SPIRV::Dim::DIM_Buffer && Sampled == 1;
1339}
1340
1341bool isInputAttachment(MachineInstr *ImageInst) {
1342 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1343 return false;
1344 uint32_t Dim = ImageInst->getOperand(2).getImm();
1345 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1346 return Dim == SPIRV::Dim::DIM_SubpassData && Sampled == 2;
1347}
1348
1349bool isStorageImage(MachineInstr *ImageInst) {
1350 if (ImageInst->getOpcode() != SPIRV::OpTypeImage)
1351 return false;
1352 uint32_t Dim = ImageInst->getOperand(2).getImm();
1353 uint32_t Sampled = ImageInst->getOperand(6).getImm();
1354 return Dim != SPIRV::Dim::DIM_Buffer && Sampled == 2;
1355}
1356
1357bool isCombinedImageSampler(MachineInstr *SampledImageInst) {
1358 if (SampledImageInst->getOpcode() != SPIRV::OpTypeSampledImage)
1359 return false;
1360
1361 const MachineRegisterInfo &MRI = SampledImageInst->getMF()->getRegInfo();
1362 Register ImageReg = SampledImageInst->getOperand(1).getReg();
1363 auto *ImageInst = MRI.getUniqueVRegDef(ImageReg);
1364 return isSampledImage(ImageInst);
1365}
1366
1367bool hasNonUniformDecoration(Register Reg, const MachineRegisterInfo &MRI) {
1368 for (const auto &MI : MRI.reg_instructions(Reg)) {
1369 if (MI.getOpcode() != SPIRV::OpDecorate)
1370 continue;
1371
1372 uint32_t Dec = MI.getOperand(1).getImm();
1373 if (Dec == SPIRV::Decoration::NonUniformEXT)
1374 return true;
1375 }
1376 return false;
1377}
1378
1379void addOpAccessChainReqs(const MachineInstr &Instr,
1381 const SPIRVSubtarget &Subtarget) {
1382 const MachineRegisterInfo &MRI = Instr.getMF()->getRegInfo();
1383 // Get the result type. If it is an image type, then the shader uses
1384 // descriptor indexing. The appropriate capabilities will be added based
1385 // on the specifics of the image.
1386 Register ResTypeReg = Instr.getOperand(1).getReg();
1387 MachineInstr *ResTypeInst = MRI.getUniqueVRegDef(ResTypeReg);
1388
1389 assert(ResTypeInst->getOpcode() == SPIRV::OpTypePointer);
1390 uint32_t StorageClass = ResTypeInst->getOperand(1).getImm();
1391 if (StorageClass != SPIRV::StorageClass::StorageClass::UniformConstant &&
1392 StorageClass != SPIRV::StorageClass::StorageClass::Uniform &&
1393 StorageClass != SPIRV::StorageClass::StorageClass::StorageBuffer) {
1394 return;
1395 }
1396
1397 bool IsNonUniform =
1398 hasNonUniformDecoration(Instr.getOperand(0).getReg(), MRI);
1399
1400 auto FirstIndexReg = Instr.getOperand(3).getReg();
1401 bool FirstIndexIsConstant =
1402 Subtarget.getInstrInfo()->isConstantInstr(*MRI.getVRegDef(FirstIndexReg));
1403
1404 if (StorageClass == SPIRV::StorageClass::StorageClass::StorageBuffer) {
1405 if (IsNonUniform)
1406 Handler.addRequirements(
1407 SPIRV::Capability::StorageBufferArrayNonUniformIndexingEXT);
1408 else if (!FirstIndexIsConstant)
1409 Handler.addRequirements(
1410 SPIRV::Capability::StorageBufferArrayDynamicIndexing);
1411 return;
1412 }
1413
1414 Register PointeeTypeReg = ResTypeInst->getOperand(2).getReg();
1415 MachineInstr *PointeeType = MRI.getUniqueVRegDef(PointeeTypeReg);
1416 if (PointeeType->getOpcode() != SPIRV::OpTypeImage &&
1417 PointeeType->getOpcode() != SPIRV::OpTypeSampledImage &&
1418 PointeeType->getOpcode() != SPIRV::OpTypeSampler) {
1419 return;
1420 }
1421
1422 if (isUniformTexelBuffer(PointeeType)) {
1423 if (IsNonUniform)
1424 Handler.addRequirements(
1425 SPIRV::Capability::UniformTexelBufferArrayNonUniformIndexingEXT);
1426 else if (!FirstIndexIsConstant)
1427 Handler.addRequirements(
1428 SPIRV::Capability::UniformTexelBufferArrayDynamicIndexingEXT);
1429 } else if (isInputAttachment(PointeeType)) {
1430 if (IsNonUniform)
1431 Handler.addRequirements(
1432 SPIRV::Capability::InputAttachmentArrayNonUniformIndexingEXT);
1433 else if (!FirstIndexIsConstant)
1434 Handler.addRequirements(
1435 SPIRV::Capability::InputAttachmentArrayDynamicIndexingEXT);
1436 } else if (isStorageTexelBuffer(PointeeType)) {
1437 if (IsNonUniform)
1438 Handler.addRequirements(
1439 SPIRV::Capability::StorageTexelBufferArrayNonUniformIndexingEXT);
1440 else if (!FirstIndexIsConstant)
1441 Handler.addRequirements(
1442 SPIRV::Capability::StorageTexelBufferArrayDynamicIndexingEXT);
1443 } else if (isSampledImage(PointeeType) ||
1444 isCombinedImageSampler(PointeeType) ||
1445 PointeeType->getOpcode() == SPIRV::OpTypeSampler) {
1446 if (IsNonUniform)
1447 Handler.addRequirements(
1448 SPIRV::Capability::SampledImageArrayNonUniformIndexingEXT);
1449 else if (!FirstIndexIsConstant)
1450 Handler.addRequirements(
1451 SPIRV::Capability::SampledImageArrayDynamicIndexing);
1452 } else if (isStorageImage(PointeeType)) {
1453 if (IsNonUniform)
1454 Handler.addRequirements(
1455 SPIRV::Capability::StorageImageArrayNonUniformIndexingEXT);
1456 else if (!FirstIndexIsConstant)
1457 Handler.addRequirements(
1458 SPIRV::Capability::StorageImageArrayDynamicIndexing);
1459 }
1460}
1461
1462static bool isImageTypeWithUnknownFormat(SPIRVTypeInst TypeInst) {
1463 if (TypeInst->getOpcode() != SPIRV::OpTypeImage)
1464 return false;
1465 assert(TypeInst->getOperand(7).isImm() && "The image format must be an imm.");
1466 return TypeInst->getOperand(7).getImm() == 0;
1467}
1468
1469static void AddDotProductRequirements(const MachineInstr &MI,
1471 const SPIRVSubtarget &ST) {
1472 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product))
1473 Reqs.addExtension(SPIRV::Extension::SPV_KHR_integer_dot_product);
1474 Reqs.addCapability(SPIRV::Capability::DotProduct);
1475
1476 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1477 assert(MI.getOperand(2).isReg() && "Unexpected operand in dot");
1478 // We do not consider what the previous instruction is. This is just used
1479 // to get the input register and to check the type.
1480 const MachineInstr *Input = MRI.getVRegDef(MI.getOperand(2).getReg());
1481 assert(Input->getOperand(1).isReg() && "Unexpected operand in dot input");
1482 Register InputReg = Input->getOperand(1).getReg();
1483
1484 SPIRVTypeInst TypeDef = MRI.getVRegDef(InputReg);
1485 if (TypeDef->getOpcode() == SPIRV::OpTypeInt) {
1486 assert(TypeDef->getOperand(1).getImm() == 32);
1487 Reqs.addCapability(SPIRV::Capability::DotProductInput4x8BitPacked);
1488 } else if (TypeDef->getOpcode() == SPIRV::OpTypeVector) {
1489 SPIRVTypeInst ScalarTypeDef =
1490 MRI.getVRegDef(TypeDef->getOperand(1).getReg());
1491 assert(ScalarTypeDef->getOpcode() == SPIRV::OpTypeInt);
1492 if (ScalarTypeDef->getOperand(1).getImm() == 8) {
1493 assert(TypeDef->getOperand(2).getImm() == 4 &&
1494 "Dot operand of 8-bit integer type requires 4 components");
1495 Reqs.addCapability(SPIRV::Capability::DotProductInput4x8Bit);
1496 } else {
1497 Reqs.addCapability(SPIRV::Capability::DotProductInputAll);
1498 }
1499 }
1500}
1501
1502void addPrintfRequirements(const MachineInstr &MI,
1504 const SPIRVSubtarget &ST) {
1505 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
1506 SPIRVTypeInst PtrType =
1507 GR->getSPIRVTypeForVReg(MI.getOperand(4).getReg(), MI.getMF());
1508 if (PtrType) {
1509 MachineOperand ASOp = PtrType->getOperand(1);
1510 if (ASOp.isImm()) {
1511 unsigned AddrSpace = ASOp.getImm();
1512 if (AddrSpace != SPIRV::StorageClass::UniformConstant) {
1513 if (!ST.canUseExtension(
1515 SPV_EXT_relaxed_printf_string_address_space)) {
1516 report_fatal_error("SPV_EXT_relaxed_printf_string_address_space is "
1517 "required because printf uses a format string not "
1518 "in constant address space.",
1519 false);
1520 }
1521 Reqs.addExtension(
1522 SPIRV::Extension::SPV_EXT_relaxed_printf_string_address_space);
1523 }
1524 }
1525 }
1526}
1527
1528static void addImageOperandReqs(const MachineInstr &MI,
1530 const SPIRVSubtarget &ST, unsigned OpIdx) {
1531 if (MI.getNumOperands() <= OpIdx)
1532 return;
1533 uint32_t Mask = MI.getOperand(OpIdx).getImm();
1534 for (uint32_t I = 0; I < 32; ++I)
1535 if (Mask & (1U << I))
1536 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ImageOperandOperand,
1537 1U << I, ST);
1538}
1539
1540void addInstrRequirements(const MachineInstr &MI,
1542 const SPIRVSubtarget &ST) {
1543 SPIRV::RequirementHandler &Reqs = MAI.Reqs;
1544 unsigned Op = MI.getOpcode();
1545 switch (Op) {
1546 case SPIRV::OpMemoryModel: {
1547 int64_t Addr = MI.getOperand(0).getImm();
1548 Reqs.getAndAddRequirements(SPIRV::OperandCategory::AddressingModelOperand,
1549 Addr, ST);
1550 int64_t Mem = MI.getOperand(1).getImm();
1551 Reqs.getAndAddRequirements(SPIRV::OperandCategory::MemoryModelOperand, Mem,
1552 ST);
1553 break;
1554 }
1555 case SPIRV::OpEntryPoint: {
1556 int64_t Exe = MI.getOperand(0).getImm();
1557 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ExecutionModelOperand,
1558 Exe, ST);
1559 break;
1560 }
1561 case SPIRV::OpExecutionMode:
1562 case SPIRV::OpExecutionModeId: {
1563 int64_t Exe = MI.getOperand(1).getImm();
1564 Reqs.getAndAddRequirements(SPIRV::OperandCategory::ExecutionModeOperand,
1565 Exe, ST);
1566 break;
1567 }
1568 case SPIRV::OpTypeMatrix:
1569 Reqs.addCapability(SPIRV::Capability::Matrix);
1570 break;
1571 case SPIRV::OpTypeInt: {
1572 unsigned BitWidth = MI.getOperand(1).getImm();
1573 if (BitWidth == 64)
1574 Reqs.addCapability(SPIRV::Capability::Int64);
1575 else if (BitWidth == 16)
1576 Reqs.addCapability(SPIRV::Capability::Int16);
1577 else if (BitWidth == 8)
1578 Reqs.addCapability(SPIRV::Capability::Int8);
1579 else if (BitWidth == 4 &&
1580 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_int4)) {
1581 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_int4);
1582 Reqs.addCapability(SPIRV::Capability::Int4TypeINTEL);
1583 } else if (BitWidth != 32) {
1584 if (!ST.canUseExtension(
1585 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers))
1587 "OpTypeInt type with a width other than 8, 16, 32 or 64 bits "
1588 "requires the following SPIR-V extension: "
1589 "SPV_ALTERA_arbitrary_precision_integers");
1590 Reqs.addExtension(
1591 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers);
1592 Reqs.addCapability(SPIRV::Capability::ArbitraryPrecisionIntegersALTERA);
1593 }
1594 break;
1595 }
1596 case SPIRV::OpDot: {
1597 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1598 SPIRVTypeInst TypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
1599 if (isBFloat16Type(TypeDef))
1600 Reqs.addCapability(SPIRV::Capability::BFloat16DotProductKHR);
1601 break;
1602 }
1603 case SPIRV::OpTypeFloat: {
1604 unsigned BitWidth = MI.getOperand(1).getImm();
1605 if (BitWidth == 64)
1606 Reqs.addCapability(SPIRV::Capability::Float64);
1607 else if (BitWidth == 16) {
1608 if (isBFloat16Type(&MI)) {
1609 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_bfloat16))
1610 report_fatal_error("OpTypeFloat type with bfloat requires the "
1611 "following SPIR-V extension: SPV_KHR_bfloat16",
1612 false);
1613 Reqs.addExtension(SPIRV::Extension::SPV_KHR_bfloat16);
1614 Reqs.addCapability(SPIRV::Capability::BFloat16TypeKHR);
1615 } else {
1616 Reqs.addCapability(SPIRV::Capability::Float16);
1617 }
1618 }
1619 break;
1620 }
1621 case SPIRV::OpTypeVector: {
1622 unsigned NumComponents = MI.getOperand(2).getImm();
1623 if (NumComponents == 8 || NumComponents == 16)
1624 Reqs.addCapability(SPIRV::Capability::Vector16);
1625
1626 assert(MI.getOperand(1).isReg());
1627 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1628 SPIRVTypeInst ElemTypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
1629 if (ElemTypeDef->getOpcode() == SPIRV::OpTypePointer &&
1630 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_masked_gather_scatter)) {
1631 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_masked_gather_scatter);
1632 Reqs.addCapability(SPIRV::Capability::MaskedGatherScatterINTEL);
1633 }
1634 break;
1635 }
1636 case SPIRV::OpTypePointer: {
1637 auto SC = MI.getOperand(1).getImm();
1638 Reqs.getAndAddRequirements(SPIRV::OperandCategory::StorageClassOperand, SC,
1639 ST);
1640 // If it's a type of pointer to float16 targeting OpenCL, add Float16Buffer
1641 // capability.
1642 if (ST.isShader())
1643 break;
1644 assert(MI.getOperand(2).isReg());
1645 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1646 SPIRVTypeInst TypeDef = MRI.getVRegDef(MI.getOperand(2).getReg());
1647 if ((TypeDef->getNumOperands() == 2) &&
1648 (TypeDef->getOpcode() == SPIRV::OpTypeFloat) &&
1649 (TypeDef->getOperand(1).getImm() == 16))
1650 Reqs.addCapability(SPIRV::Capability::Float16Buffer);
1651 break;
1652 }
1653 case SPIRV::OpExtInst: {
1654 if (MI.getOperand(2).getImm() ==
1655 static_cast<int64_t>(
1656 SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100)) {
1657 Reqs.addExtension(SPIRV::Extension::SPV_KHR_non_semantic_info);
1658 break;
1659 }
1660 if (MI.getOperand(3).getImm() ==
1661 static_cast<int64_t>(SPIRV::OpenCLExtInst::printf)) {
1662 addPrintfRequirements(MI, Reqs, ST);
1663 break;
1664 }
1665 // TODO: handle bfloat16 extended instructions when
1666 // SPV_INTEL_bfloat16_arithmetic is enabled.
1667 break;
1668 }
1669 case SPIRV::OpAliasDomainDeclINTEL:
1670 case SPIRV::OpAliasScopeDeclINTEL:
1671 case SPIRV::OpAliasScopeListDeclINTEL: {
1672 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing);
1673 Reqs.addCapability(SPIRV::Capability::MemoryAccessAliasingINTEL);
1674 break;
1675 }
1676 case SPIRV::OpBitReverse:
1677 case SPIRV::OpBitFieldInsert:
1678 case SPIRV::OpBitFieldSExtract:
1679 case SPIRV::OpBitFieldUExtract:
1680 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions)) {
1681 Reqs.addCapability(SPIRV::Capability::Shader);
1682 break;
1683 }
1684 Reqs.addExtension(SPIRV::Extension::SPV_KHR_bit_instructions);
1685 Reqs.addCapability(SPIRV::Capability::BitInstructions);
1686 break;
1687 case SPIRV::OpTypeRuntimeArray:
1688 Reqs.addCapability(SPIRV::Capability::Shader);
1689 break;
1690 case SPIRV::OpTypeOpaque:
1691 case SPIRV::OpTypeEvent:
1692 Reqs.addCapability(SPIRV::Capability::Kernel);
1693 break;
1694 case SPIRV::OpTypePipe:
1695 case SPIRV::OpTypeReserveId:
1696 Reqs.addCapability(SPIRV::Capability::Pipes);
1697 break;
1698 case SPIRV::OpTypeDeviceEvent:
1699 case SPIRV::OpTypeQueue:
1700 case SPIRV::OpBuildNDRange:
1701 case SPIRV::OpEnqueueKernel:
1702 Reqs.addCapability(SPIRV::Capability::DeviceEnqueue);
1703 break;
1704 case SPIRV::OpDecorate:
1705 case SPIRV::OpDecorateId:
1706 case SPIRV::OpDecorateString:
1707 addOpDecorateReqs(MI, 1, Reqs, ST);
1708 break;
1709 case SPIRV::OpMemberDecorate:
1710 case SPIRV::OpMemberDecorateString:
1711 addOpDecorateReqs(MI, 2, Reqs, ST);
1712 break;
1713 case SPIRV::OpInBoundsPtrAccessChain:
1714 Reqs.addCapability(SPIRV::Capability::Addresses);
1715 break;
1716 case SPIRV::OpConstantSampler:
1717 Reqs.addCapability(SPIRV::Capability::LiteralSampler);
1718 break;
1719 case SPIRV::OpInBoundsAccessChain:
1720 case SPIRV::OpAccessChain:
1721 addOpAccessChainReqs(MI, Reqs, ST);
1722 break;
1723 case SPIRV::OpTypeImage:
1724 addOpTypeImageReqs(MI, Reqs, ST);
1725 break;
1726 case SPIRV::OpTypeSampler:
1727 if (!ST.isShader()) {
1728 Reqs.addCapability(SPIRV::Capability::ImageBasic);
1729 }
1730 break;
1731 case SPIRV::OpTypeForwardPointer:
1732 // TODO: check if it's OpenCL's kernel.
1733 Reqs.addCapability(SPIRV::Capability::Addresses);
1734 break;
1735 case SPIRV::OpAtomicFlagTestAndSet:
1736 case SPIRV::OpAtomicLoad:
1737 case SPIRV::OpAtomicStore:
1738 case SPIRV::OpAtomicExchange:
1739 case SPIRV::OpAtomicCompareExchange:
1740 case SPIRV::OpAtomicIIncrement:
1741 case SPIRV::OpAtomicIDecrement:
1742 case SPIRV::OpAtomicIAdd:
1743 case SPIRV::OpAtomicISub:
1744 case SPIRV::OpAtomicUMin:
1745 case SPIRV::OpAtomicUMax:
1746 case SPIRV::OpAtomicSMin:
1747 case SPIRV::OpAtomicSMax:
1748 case SPIRV::OpAtomicAnd:
1749 case SPIRV::OpAtomicOr:
1750 case SPIRV::OpAtomicXor: {
1751 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1752 const MachineInstr *InstrPtr = &MI;
1753 if (Op == SPIRV::OpAtomicStore) {
1754 assert(MI.getOperand(3).isReg());
1755 InstrPtr = MRI.getVRegDef(MI.getOperand(3).getReg());
1756 assert(InstrPtr && "Unexpected type instruction for OpAtomicStore");
1757 }
1758 assert(InstrPtr->getOperand(1).isReg() && "Unexpected operand in atomic");
1759 Register TypeReg = InstrPtr->getOperand(1).getReg();
1760 SPIRVTypeInst TypeDef = MRI.getVRegDef(TypeReg);
1761
1762 if (TypeDef->getOpcode() == SPIRV::OpTypeInt) {
1763 unsigned BitWidth = TypeDef->getOperand(1).getImm();
1764 if (BitWidth == 64)
1765 Reqs.addCapability(SPIRV::Capability::Int64Atomics);
1766 else if (BitWidth == 16) {
1767 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics))
1769 "16-bit integer atomic operations require the following SPIR-V "
1770 "extension: SPV_INTEL_16bit_atomics",
1771 false);
1772 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics);
1773 switch (Op) {
1774 case SPIRV::OpAtomicLoad:
1775 case SPIRV::OpAtomicStore:
1776 case SPIRV::OpAtomicExchange:
1777 case SPIRV::OpAtomicCompareExchange:
1778 case SPIRV::OpAtomicCompareExchangeWeak:
1779 Reqs.addCapability(
1780 SPIRV::Capability::AtomicInt16CompareExchangeINTEL);
1781 break;
1782 default:
1783 Reqs.addCapability(SPIRV::Capability::Int16AtomicsINTEL);
1784 break;
1785 }
1786 }
1787 } else if (isBFloat16Type(TypeDef)) {
1788 if (is_contained({SPIRV::OpAtomicLoad, SPIRV::OpAtomicStore,
1789 SPIRV::OpAtomicExchange},
1790 Op)) {
1791 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics))
1793 "The atomic bfloat16 instruction requires the following SPIR-V "
1794 "extension: SPV_INTEL_16bit_atomics",
1795 false);
1796 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_16bit_atomics);
1797 Reqs.addCapability(SPIRV::Capability::AtomicBFloat16LoadStoreINTEL);
1798 }
1799 }
1800 break;
1801 }
1802 case SPIRV::OpGroupNonUniformIAdd:
1803 case SPIRV::OpGroupNonUniformFAdd:
1804 case SPIRV::OpGroupNonUniformIMul:
1805 case SPIRV::OpGroupNonUniformFMul:
1806 case SPIRV::OpGroupNonUniformSMin:
1807 case SPIRV::OpGroupNonUniformUMin:
1808 case SPIRV::OpGroupNonUniformFMin:
1809 case SPIRV::OpGroupNonUniformSMax:
1810 case SPIRV::OpGroupNonUniformUMax:
1811 case SPIRV::OpGroupNonUniformFMax:
1812 case SPIRV::OpGroupNonUniformBitwiseAnd:
1813 case SPIRV::OpGroupNonUniformBitwiseOr:
1814 case SPIRV::OpGroupNonUniformBitwiseXor:
1815 case SPIRV::OpGroupNonUniformLogicalAnd:
1816 case SPIRV::OpGroupNonUniformLogicalOr:
1817 case SPIRV::OpGroupNonUniformLogicalXor: {
1818 assert(MI.getOperand(3).isImm());
1819 int64_t GroupOp = MI.getOperand(3).getImm();
1820 switch (GroupOp) {
1821 case SPIRV::GroupOperation::Reduce:
1822 case SPIRV::GroupOperation::InclusiveScan:
1823 case SPIRV::GroupOperation::ExclusiveScan:
1824 Reqs.addCapability(SPIRV::Capability::GroupNonUniformArithmetic);
1825 break;
1826 case SPIRV::GroupOperation::ClusteredReduce:
1827 Reqs.addCapability(SPIRV::Capability::GroupNonUniformClustered);
1828 break;
1829 case SPIRV::GroupOperation::PartitionedReduceNV:
1830 case SPIRV::GroupOperation::PartitionedInclusiveScanNV:
1831 case SPIRV::GroupOperation::PartitionedExclusiveScanNV:
1832 Reqs.addCapability(SPIRV::Capability::GroupNonUniformPartitionedNV);
1833 break;
1834 }
1835 break;
1836 }
1837 case SPIRV::OpGroupNonUniformQuadSwap:
1838 Reqs.addCapability(SPIRV::Capability::GroupNonUniformQuad);
1839 break;
1840 case SPIRV::OpImageQueryLod:
1841 Reqs.addCapability(SPIRV::Capability::ImageQuery);
1842 break;
1843 case SPIRV::OpImageQuerySize:
1844 case SPIRV::OpImageQuerySizeLod:
1845 case SPIRV::OpImageQueryLevels:
1846 case SPIRV::OpImageQuerySamples:
1847 if (ST.isShader())
1848 Reqs.addCapability(SPIRV::Capability::ImageQuery);
1849 break;
1850 case SPIRV::OpImageQueryFormat: {
1851 Register ResultReg = MI.getOperand(0).getReg();
1852 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
1853 static const unsigned CompareOps[] = {
1854 SPIRV::OpIEqual, SPIRV::OpINotEqual,
1855 SPIRV::OpUGreaterThan, SPIRV::OpUGreaterThanEqual,
1856 SPIRV::OpULessThan, SPIRV::OpULessThanEqual,
1857 SPIRV::OpSGreaterThan, SPIRV::OpSGreaterThanEqual,
1858 SPIRV::OpSLessThan, SPIRV::OpSLessThanEqual};
1859
1860 auto CheckAndAddExtension = [&](int64_t ImmVal) {
1861 if (ImmVal == 4323 || ImmVal == 4324) {
1862 if (ST.canUseExtension(SPIRV::Extension::SPV_EXT_image_raw10_raw12))
1863 Reqs.addExtension(SPIRV::Extension::SPV_EXT_image_raw10_raw12);
1864 else
1865 report_fatal_error("This requires the "
1866 "SPV_EXT_image_raw10_raw12 extension");
1867 }
1868 };
1869
1870 for (MachineInstr &UseInst : MRI.use_instructions(ResultReg)) {
1871 unsigned Opc = UseInst.getOpcode();
1872
1873 if (Opc == SPIRV::OpSwitch) {
1874 for (const MachineOperand &Op : UseInst.operands())
1875 if (Op.isImm())
1876 CheckAndAddExtension(Op.getImm());
1877 } else if (llvm::is_contained(CompareOps, Opc)) {
1878 for (unsigned i = 1; i < UseInst.getNumOperands(); ++i) {
1879 Register UseReg = UseInst.getOperand(i).getReg();
1880 MachineInstr *ConstInst = MRI.getVRegDef(UseReg);
1881 if (ConstInst && ConstInst->getOpcode() == SPIRV::OpConstantI) {
1882 int64_t ImmVal = ConstInst->getOperand(2).getImm();
1883 if (ImmVal)
1884 CheckAndAddExtension(ImmVal);
1885 }
1886 }
1887 }
1888 }
1889 break;
1890 }
1891
1892 case SPIRV::OpGroupNonUniformShuffle:
1893 case SPIRV::OpGroupNonUniformShuffleXor:
1894 Reqs.addCapability(SPIRV::Capability::GroupNonUniformShuffle);
1895 break;
1896 case SPIRV::OpGroupNonUniformShuffleUp:
1897 case SPIRV::OpGroupNonUniformShuffleDown:
1898 Reqs.addCapability(SPIRV::Capability::GroupNonUniformShuffleRelative);
1899 break;
1900 case SPIRV::OpGroupAll:
1901 case SPIRV::OpGroupAny:
1902 case SPIRV::OpGroupBroadcast:
1903 case SPIRV::OpGroupIAdd:
1904 case SPIRV::OpGroupFAdd:
1905 case SPIRV::OpGroupFMin:
1906 case SPIRV::OpGroupUMin:
1907 case SPIRV::OpGroupSMin:
1908 case SPIRV::OpGroupFMax:
1909 case SPIRV::OpGroupUMax:
1910 case SPIRV::OpGroupSMax:
1911 Reqs.addCapability(SPIRV::Capability::Groups);
1912 break;
1913 case SPIRV::OpGroupNonUniformElect:
1914 Reqs.addCapability(SPIRV::Capability::GroupNonUniform);
1915 break;
1916 case SPIRV::OpGroupNonUniformAll:
1917 case SPIRV::OpGroupNonUniformAny:
1918 case SPIRV::OpGroupNonUniformAllEqual:
1919 Reqs.addCapability(SPIRV::Capability::GroupNonUniformVote);
1920 break;
1921 case SPIRV::OpGroupNonUniformBroadcast:
1922 case SPIRV::OpGroupNonUniformBroadcastFirst:
1923 case SPIRV::OpGroupNonUniformBallot:
1924 case SPIRV::OpGroupNonUniformInverseBallot:
1925 case SPIRV::OpGroupNonUniformBallotBitExtract:
1926 case SPIRV::OpGroupNonUniformBallotBitCount:
1927 case SPIRV::OpGroupNonUniformBallotFindLSB:
1928 case SPIRV::OpGroupNonUniformBallotFindMSB:
1929 Reqs.addCapability(SPIRV::Capability::GroupNonUniformBallot);
1930 break;
1931 case SPIRV::OpSubgroupShuffleINTEL:
1932 case SPIRV::OpSubgroupShuffleDownINTEL:
1933 case SPIRV::OpSubgroupShuffleUpINTEL:
1934 case SPIRV::OpSubgroupShuffleXorINTEL:
1935 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
1936 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
1937 Reqs.addCapability(SPIRV::Capability::SubgroupShuffleINTEL);
1938 }
1939 break;
1940 case SPIRV::OpSubgroupBlockReadINTEL:
1941 case SPIRV::OpSubgroupBlockWriteINTEL:
1942 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
1943 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
1944 Reqs.addCapability(SPIRV::Capability::SubgroupBufferBlockIOINTEL);
1945 }
1946 break;
1947 case SPIRV::OpSubgroupImageBlockReadINTEL:
1948 case SPIRV::OpSubgroupImageBlockWriteINTEL:
1949 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
1950 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_subgroups);
1951 Reqs.addCapability(SPIRV::Capability::SubgroupImageBlockIOINTEL);
1952 }
1953 break;
1954 case SPIRV::OpSubgroupImageMediaBlockReadINTEL:
1955 case SPIRV::OpSubgroupImageMediaBlockWriteINTEL:
1956 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_media_block_io)) {
1957 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_media_block_io);
1958 Reqs.addCapability(SPIRV::Capability::SubgroupImageMediaBlockIOINTEL);
1959 }
1960 break;
1961 case SPIRV::OpAssumeTrueKHR:
1962 case SPIRV::OpExpectKHR:
1963 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume)) {
1964 Reqs.addExtension(SPIRV::Extension::SPV_KHR_expect_assume);
1965 Reqs.addCapability(SPIRV::Capability::ExpectAssumeKHR);
1966 }
1967 break;
1968 case SPIRV::OpFmaKHR:
1969 if (ST.canUseExtension(SPIRV::Extension::SPV_KHR_fma)) {
1970 Reqs.addExtension(SPIRV::Extension::SPV_KHR_fma);
1971 Reqs.addCapability(SPIRV::Capability::FmaKHR);
1972 }
1973 break;
1974 case SPIRV::OpPtrCastToCrossWorkgroupINTEL:
1975 case SPIRV::OpCrossWorkgroupCastToPtrINTEL:
1976 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes)) {
1977 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes);
1978 Reqs.addCapability(SPIRV::Capability::USMStorageClassesINTEL);
1979 }
1980 break;
1981 case SPIRV::OpConstantFunctionPointerINTEL:
1982 case SPIRV::OpFunctionPointerCallINTEL:
1983 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)) {
1984 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
1985 Reqs.addCapability(SPIRV::Capability::FunctionPointersINTEL);
1986 }
1987 break;
1988 case SPIRV::OpGroupNonUniformRotateKHR:
1989 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_subgroup_rotate))
1990 report_fatal_error("OpGroupNonUniformRotateKHR instruction requires the "
1991 "following SPIR-V extension: SPV_KHR_subgroup_rotate",
1992 false);
1993 Reqs.addExtension(SPIRV::Extension::SPV_KHR_subgroup_rotate);
1994 Reqs.addCapability(SPIRV::Capability::GroupNonUniformRotateKHR);
1995 Reqs.addCapability(SPIRV::Capability::GroupNonUniform);
1996 break;
1997 case SPIRV::OpFixedCosALTERA:
1998 case SPIRV::OpFixedSinALTERA:
1999 case SPIRV::OpFixedCosPiALTERA:
2000 case SPIRV::OpFixedSinPiALTERA:
2001 case SPIRV::OpFixedExpALTERA:
2002 case SPIRV::OpFixedLogALTERA:
2003 case SPIRV::OpFixedRecipALTERA:
2004 case SPIRV::OpFixedSqrtALTERA:
2005 case SPIRV::OpFixedSinCosALTERA:
2006 case SPIRV::OpFixedSinCosPiALTERA:
2007 case SPIRV::OpFixedRsqrtALTERA:
2008 if (!ST.canUseExtension(
2009 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_fixed_point))
2010 report_fatal_error("This instruction requires the "
2011 "following SPIR-V extension: "
2012 "SPV_ALTERA_arbitrary_precision_fixed_point",
2013 false);
2014 Reqs.addExtension(
2015 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_fixed_point);
2016 Reqs.addCapability(SPIRV::Capability::ArbitraryPrecisionFixedPointALTERA);
2017 break;
2018 case SPIRV::OpGroupIMulKHR:
2019 case SPIRV::OpGroupFMulKHR:
2020 case SPIRV::OpGroupBitwiseAndKHR:
2021 case SPIRV::OpGroupBitwiseOrKHR:
2022 case SPIRV::OpGroupBitwiseXorKHR:
2023 case SPIRV::OpGroupLogicalAndKHR:
2024 case SPIRV::OpGroupLogicalOrKHR:
2025 case SPIRV::OpGroupLogicalXorKHR:
2026 if (ST.canUseExtension(
2027 SPIRV::Extension::SPV_KHR_uniform_group_instructions)) {
2028 Reqs.addExtension(SPIRV::Extension::SPV_KHR_uniform_group_instructions);
2029 Reqs.addCapability(SPIRV::Capability::GroupUniformArithmeticKHR);
2030 }
2031 break;
2032 case SPIRV::OpReadClockKHR:
2033 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_shader_clock))
2034 report_fatal_error("OpReadClockKHR instruction requires the "
2035 "following SPIR-V extension: SPV_KHR_shader_clock",
2036 false);
2037 Reqs.addExtension(SPIRV::Extension::SPV_KHR_shader_clock);
2038 Reqs.addCapability(SPIRV::Capability::ShaderClockKHR);
2039 break;
2040 case SPIRV::OpAbortKHR:
2041 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort))
2042 report_fatal_error("OpAbortKHR instruction requires the "
2043 "following SPIR-V extension: SPV_KHR_abort",
2044 false);
2045 Reqs.addExtension(SPIRV::Extension::SPV_KHR_abort);
2046 Reqs.addCapability(SPIRV::Capability::AbortKHR);
2047 break;
2048 case SPIRV::OpPoisonKHR:
2049 case SPIRV::OpFreezeKHR:
2050 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_poison_freeze))
2051 report_fatal_error("OpPoisonKHR/OpFreezeKHR instruction requires the "
2052 "following SPIR-V extension: SPV_KHR_poison_freeze",
2053 false);
2054 Reqs.addExtension(SPIRV::Extension::SPV_KHR_poison_freeze);
2055 Reqs.addCapability(SPIRV::Capability::PoisonFreezeKHR);
2056 break;
2057 case SPIRV::OpAtomicFAddEXT:
2058 case SPIRV::OpAtomicFMinEXT:
2059 case SPIRV::OpAtomicFMaxEXT:
2060 AddAtomicFloatRequirements(MI, Reqs, ST);
2061 break;
2062 case SPIRV::OpConvertBF16ToFINTEL:
2063 case SPIRV::OpConvertFToBF16INTEL:
2064 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bfloat16_conversion)) {
2065 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_conversion);
2066 Reqs.addCapability(SPIRV::Capability::BFloat16ConversionINTEL);
2067 }
2068 break;
2069 case SPIRV::OpRoundFToTF32INTEL:
2070 if (ST.canUseExtension(
2071 SPIRV::Extension::SPV_INTEL_tensor_float32_conversion)) {
2072 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_tensor_float32_conversion);
2073 Reqs.addCapability(SPIRV::Capability::TensorFloat32RoundingINTEL);
2074 }
2075 break;
2076 case SPIRV::OpVariableLengthArrayINTEL:
2077 case SPIRV::OpSaveMemoryINTEL:
2078 case SPIRV::OpRestoreMemoryINTEL:
2079 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array)) {
2080 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_variable_length_array);
2081 Reqs.addCapability(SPIRV::Capability::VariableLengthArrayINTEL);
2082 }
2083 break;
2084 case SPIRV::OpAsmTargetINTEL:
2085 case SPIRV::OpAsmINTEL:
2086 case SPIRV::OpAsmCallINTEL:
2087 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_inline_assembly)) {
2088 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_inline_assembly);
2089 Reqs.addCapability(SPIRV::Capability::AsmINTEL);
2090 }
2091 break;
2092 case SPIRV::OpTypeCooperativeMatrixKHR: {
2093 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix))
2095 "OpTypeCooperativeMatrixKHR type requires the "
2096 "following SPIR-V extension: SPV_KHR_cooperative_matrix",
2097 false);
2098 Reqs.addExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix);
2099 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixKHR);
2100 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
2101 SPIRVTypeInst TypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
2102 if (isBFloat16Type(TypeDef))
2103 Reqs.addCapability(SPIRV::Capability::BFloat16CooperativeMatrixKHR);
2104 break;
2105 }
2106 case SPIRV::OpArithmeticFenceEXT:
2107 if (!ST.canUseExtension(SPIRV::Extension::SPV_EXT_arithmetic_fence))
2108 report_fatal_error("OpArithmeticFenceEXT requires the "
2109 "following SPIR-V extension: SPV_EXT_arithmetic_fence",
2110 false);
2111 Reqs.addExtension(SPIRV::Extension::SPV_EXT_arithmetic_fence);
2112 Reqs.addCapability(SPIRV::Capability::ArithmeticFenceEXT);
2113 break;
2114 case SPIRV::OpControlBarrierArriveINTEL:
2115 case SPIRV::OpControlBarrierWaitINTEL:
2116 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_split_barrier)) {
2117 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_split_barrier);
2118 Reqs.addCapability(SPIRV::Capability::SplitBarrierINTEL);
2119 }
2120 break;
2121 case SPIRV::OpCooperativeMatrixMulAddKHR: {
2122 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix))
2123 report_fatal_error("Cooperative matrix instructions require the "
2124 "following SPIR-V extension: "
2125 "SPV_KHR_cooperative_matrix",
2126 false);
2127 Reqs.addExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix);
2128 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixKHR);
2129 constexpr unsigned MulAddMaxSize = 6;
2130 if (MI.getNumOperands() != MulAddMaxSize)
2131 break;
2132 const int64_t CoopOperands = MI.getOperand(MulAddMaxSize - 1).getImm();
2133 if (CoopOperands &
2134 SPIRV::CooperativeMatrixOperands::MatrixAAndBTF32ComponentsINTEL) {
2135 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2136 report_fatal_error("MatrixAAndBTF32ComponentsINTEL type interpretation "
2137 "require the following SPIR-V extension: "
2138 "SPV_INTEL_joint_matrix",
2139 false);
2140 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2141 Reqs.addCapability(
2142 SPIRV::Capability::CooperativeMatrixTF32ComponentTypeINTEL);
2143 }
2144 if (CoopOperands & SPIRV::CooperativeMatrixOperands::
2145 MatrixAAndBBFloat16ComponentsINTEL ||
2146 CoopOperands &
2147 SPIRV::CooperativeMatrixOperands::MatrixCBFloat16ComponentsINTEL ||
2148 CoopOperands & SPIRV::CooperativeMatrixOperands::
2149 MatrixResultBFloat16ComponentsINTEL) {
2150 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2151 report_fatal_error("***BF16ComponentsINTEL type interpretations "
2152 "require the following SPIR-V extension: "
2153 "SPV_INTEL_joint_matrix",
2154 false);
2155 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2156 Reqs.addCapability(
2157 SPIRV::Capability::CooperativeMatrixBFloat16ComponentTypeINTEL);
2158 }
2159 break;
2160 }
2161 case SPIRV::OpCooperativeMatrixLoadKHR:
2162 case SPIRV::OpCooperativeMatrixStoreKHR:
2163 case SPIRV::OpCooperativeMatrixLoadCheckedINTEL:
2164 case SPIRV::OpCooperativeMatrixStoreCheckedINTEL:
2165 case SPIRV::OpCooperativeMatrixPrefetchINTEL: {
2166 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix))
2167 report_fatal_error("Cooperative matrix instructions require the "
2168 "following SPIR-V extension: "
2169 "SPV_KHR_cooperative_matrix",
2170 false);
2171 Reqs.addExtension(SPIRV::Extension::SPV_KHR_cooperative_matrix);
2172 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixKHR);
2173
2174 // Check Layout operand in case if it's not a standard one and add the
2175 // appropriate capability.
2176 unsigned LayoutNum;
2177 switch (Op) {
2178 case SPIRV::OpCooperativeMatrixLoadKHR:
2179 LayoutNum = 3;
2180 break;
2181 case SPIRV::OpCooperativeMatrixStoreKHR:
2182 LayoutNum = 2;
2183 break;
2184 case SPIRV::OpCooperativeMatrixLoadCheckedINTEL:
2185 LayoutNum = 5;
2186 break;
2187 case SPIRV::OpCooperativeMatrixStoreCheckedINTEL:
2188 case SPIRV::OpCooperativeMatrixPrefetchINTEL:
2189 LayoutNum = 4;
2190 break;
2191 default:
2192 llvm_unreachable("unexpected cooperative matrix opcode");
2193 }
2194 Register RegLayout = MI.getOperand(LayoutNum).getReg();
2195 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
2196 MachineInstr *MILayout = MRI.getUniqueVRegDef(RegLayout);
2197 if (MILayout->getOpcode() == SPIRV::OpConstantI) {
2198 const unsigned LayoutVal = MILayout->getOperand(2).getImm();
2199 if (LayoutVal ==
2200 static_cast<unsigned>(SPIRV::CooperativeMatrixLayout::PackedINTEL)) {
2201 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2202 report_fatal_error("PackedINTEL layout require the following SPIR-V "
2203 "extension: SPV_INTEL_joint_matrix",
2204 false);
2205 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2206 Reqs.addCapability(SPIRV::Capability::PackedCooperativeMatrixINTEL);
2207 }
2208 }
2209
2210 // Nothing to do.
2211 if (Op == SPIRV::OpCooperativeMatrixLoadKHR ||
2212 Op == SPIRV::OpCooperativeMatrixStoreKHR)
2213 break;
2214
2215 std::string InstName;
2216 switch (Op) {
2217 case SPIRV::OpCooperativeMatrixPrefetchINTEL:
2218 InstName = "OpCooperativeMatrixPrefetchINTEL";
2219 break;
2220 case SPIRV::OpCooperativeMatrixLoadCheckedINTEL:
2221 InstName = "OpCooperativeMatrixLoadCheckedINTEL";
2222 break;
2223 case SPIRV::OpCooperativeMatrixStoreCheckedINTEL:
2224 InstName = "OpCooperativeMatrixStoreCheckedINTEL";
2225 break;
2226 }
2227
2228 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix)) {
2229 const std::string ErrorMsg =
2230 InstName + " instruction requires the "
2231 "following SPIR-V extension: SPV_INTEL_joint_matrix";
2232 report_fatal_error(ErrorMsg.c_str(), false);
2233 }
2234 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2235 if (Op == SPIRV::OpCooperativeMatrixPrefetchINTEL) {
2236 Reqs.addCapability(SPIRV::Capability::CooperativeMatrixPrefetchINTEL);
2237 break;
2238 }
2239 Reqs.addCapability(
2240 SPIRV::Capability::CooperativeMatrixCheckedInstructionsINTEL);
2241 break;
2242 }
2243 case SPIRV::OpCooperativeMatrixConstructCheckedINTEL:
2244 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2245 report_fatal_error("OpCooperativeMatrixConstructCheckedINTEL "
2246 "instructions require the following SPIR-V extension: "
2247 "SPV_INTEL_joint_matrix",
2248 false);
2249 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2250 Reqs.addCapability(
2251 SPIRV::Capability::CooperativeMatrixCheckedInstructionsINTEL);
2252 break;
2253 case SPIRV::OpReadPipeBlockingALTERA:
2254 case SPIRV::OpWritePipeBlockingALTERA:
2255 if (ST.canUseExtension(SPIRV::Extension::SPV_ALTERA_blocking_pipes)) {
2256 Reqs.addExtension(SPIRV::Extension::SPV_ALTERA_blocking_pipes);
2257 Reqs.addCapability(SPIRV::Capability::BlockingPipesALTERA);
2258 }
2259 break;
2260 case SPIRV::OpCooperativeMatrixGetElementCoordINTEL:
2261 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_joint_matrix))
2262 report_fatal_error("OpCooperativeMatrixGetElementCoordINTEL requires the "
2263 "following SPIR-V extension: SPV_INTEL_joint_matrix",
2264 false);
2265 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_joint_matrix);
2266 Reqs.addCapability(
2267 SPIRV::Capability::CooperativeMatrixInvocationInstructionsINTEL);
2268 break;
2269 case SPIRV::OpConvertHandleToImageINTEL:
2270 case SPIRV::OpConvertHandleToSamplerINTEL:
2271 case SPIRV::OpConvertHandleToSampledImageINTEL: {
2272 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bindless_images))
2273 report_fatal_error("OpConvertHandleTo[Image/Sampler/SampledImage]INTEL "
2274 "instructions require the following SPIR-V extension: "
2275 "SPV_INTEL_bindless_images",
2276 false);
2277 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
2278 SPIRV::AddressingModel::AddressingModel AddrModel = MAI.Addr;
2279 SPIRVTypeInst TyDef = GR->getSPIRVTypeForVReg(MI.getOperand(1).getReg());
2280 if (Op == SPIRV::OpConvertHandleToImageINTEL &&
2281 TyDef->getOpcode() != SPIRV::OpTypeImage) {
2282 report_fatal_error("Incorrect return type for the instruction "
2283 "OpConvertHandleToImageINTEL",
2284 false);
2285 } else if (Op == SPIRV::OpConvertHandleToSamplerINTEL &&
2286 TyDef->getOpcode() != SPIRV::OpTypeSampler) {
2287 report_fatal_error("Incorrect return type for the instruction "
2288 "OpConvertHandleToSamplerINTEL",
2289 false);
2290 } else if (Op == SPIRV::OpConvertHandleToSampledImageINTEL &&
2291 TyDef->getOpcode() != SPIRV::OpTypeSampledImage) {
2292 report_fatal_error("Incorrect return type for the instruction "
2293 "OpConvertHandleToSampledImageINTEL",
2294 false);
2295 }
2296 SPIRVTypeInst SpvTy = GR->getSPIRVTypeForVReg(MI.getOperand(2).getReg());
2297 unsigned Bitwidth = GR->getScalarOrVectorBitWidth(SpvTy);
2298 if (!(Bitwidth == 32 && AddrModel == SPIRV::AddressingModel::Physical32) &&
2299 !(Bitwidth == 64 && AddrModel == SPIRV::AddressingModel::Physical64)) {
2301 "Parameter value must be a 32-bit scalar in case of "
2302 "Physical32 addressing model or a 64-bit scalar in case of "
2303 "Physical64 addressing model",
2304 false);
2305 }
2306 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bindless_images);
2307 Reqs.addCapability(SPIRV::Capability::BindlessImagesINTEL);
2308 break;
2309 }
2310 case SPIRV::OpSubgroup2DBlockLoadINTEL:
2311 case SPIRV::OpSubgroup2DBlockLoadTransposeINTEL:
2312 case SPIRV::OpSubgroup2DBlockLoadTransformINTEL:
2313 case SPIRV::OpSubgroup2DBlockPrefetchINTEL:
2314 case SPIRV::OpSubgroup2DBlockStoreINTEL: {
2315 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_2d_block_io))
2316 report_fatal_error("OpSubgroup2DBlock[Load/LoadTranspose/LoadTransform/"
2317 "Prefetch/Store]INTEL instructions require the "
2318 "following SPIR-V extension: SPV_INTEL_2d_block_io",
2319 false);
2320 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_2d_block_io);
2321 Reqs.addCapability(SPIRV::Capability::Subgroup2DBlockIOINTEL);
2322
2323 if (Op == SPIRV::OpSubgroup2DBlockLoadTransposeINTEL) {
2324 Reqs.addCapability(SPIRV::Capability::Subgroup2DBlockTransposeINTEL);
2325 break;
2326 }
2327 if (Op == SPIRV::OpSubgroup2DBlockLoadTransformINTEL) {
2328 Reqs.addCapability(SPIRV::Capability::Subgroup2DBlockTransformINTEL);
2329 break;
2330 }
2331 break;
2332 }
2333 case SPIRV::OpKill: {
2334 Reqs.addCapability(SPIRV::Capability::Shader);
2335 } break;
2336 case SPIRV::OpDemoteToHelperInvocation:
2337 Reqs.addCapability(SPIRV::Capability::DemoteToHelperInvocation);
2338
2339 if (ST.canUseExtension(
2340 SPIRV::Extension::SPV_EXT_demote_to_helper_invocation)) {
2341 if (!ST.isAtLeastSPIRVVer(llvm::VersionTuple(1, 6)))
2342 Reqs.addExtension(
2343 SPIRV::Extension::SPV_EXT_demote_to_helper_invocation);
2344 }
2345 break;
2346 case SPIRV::OpSDot:
2347 case SPIRV::OpUDot:
2348 case SPIRV::OpSUDot:
2349 case SPIRV::OpSDotAccSat:
2350 case SPIRV::OpUDotAccSat:
2351 case SPIRV::OpSUDotAccSat:
2352 AddDotProductRequirements(MI, Reqs, ST);
2353 break;
2354 case SPIRV::OpImageSampleImplicitLod:
2355 case SPIRV::OpImageFetch:
2356 Reqs.addCapability(SPIRV::Capability::Shader);
2357 addImageOperandReqs(MI, Reqs, ST, 4);
2358 break;
2359 case SPIRV::OpImageSampleExplicitLod:
2360 addImageOperandReqs(MI, Reqs, ST, 4);
2361 break;
2362 case SPIRV::OpImageSampleDrefImplicitLod:
2363 case SPIRV::OpImageSampleDrefExplicitLod:
2364 case SPIRV::OpImageDrefGather:
2365 case SPIRV::OpImageGather:
2366 Reqs.addCapability(SPIRV::Capability::Shader);
2367 addImageOperandReqs(MI, Reqs, ST, 5);
2368 break;
2369 case SPIRV::OpImageRead: {
2370 Register ImageReg = MI.getOperand(2).getReg();
2371 SPIRVTypeInst TypeDef = ST.getSPIRVGlobalRegistry()->getResultType(
2372 ImageReg, const_cast<MachineFunction *>(MI.getMF()));
2373 // OpImageRead and OpImageWrite can use Unknown Image Formats
2374 // when the Kernel capability is declared. In the OpenCL environment we are
2375 // not allowed to produce
2376 // StorageImageReadWithoutFormat/StorageImageWriteWithoutFormat, see
2377 // https://github.com/KhronosGroup/SPIRV-Headers/issues/487
2378
2379 if (isImageTypeWithUnknownFormat(TypeDef) && ST.isShader())
2380 Reqs.addCapability(SPIRV::Capability::StorageImageReadWithoutFormat);
2381 break;
2382 }
2383 case SPIRV::OpImageWrite: {
2384 Register ImageReg = MI.getOperand(0).getReg();
2385 SPIRVTypeInst TypeDef = ST.getSPIRVGlobalRegistry()->getResultType(
2386 ImageReg, const_cast<MachineFunction *>(MI.getMF()));
2387 // OpImageRead and OpImageWrite can use Unknown Image Formats
2388 // when the Kernel capability is declared. In the OpenCL environment we are
2389 // not allowed to produce
2390 // StorageImageReadWithoutFormat/StorageImageWriteWithoutFormat, see
2391 // https://github.com/KhronosGroup/SPIRV-Headers/issues/487
2392
2393 if (isImageTypeWithUnknownFormat(TypeDef) && ST.isShader())
2394 Reqs.addCapability(SPIRV::Capability::StorageImageWriteWithoutFormat);
2395 break;
2396 }
2397 case SPIRV::OpTypeStructContinuedINTEL:
2398 case SPIRV::OpConstantCompositeContinuedINTEL:
2399 case SPIRV::OpSpecConstantCompositeContinuedINTEL:
2400 case SPIRV::OpCompositeConstructContinuedINTEL: {
2401 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_long_composites))
2403 "Continued instructions require the "
2404 "following SPIR-V extension: SPV_INTEL_long_composites",
2405 false);
2406 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_long_composites);
2407 Reqs.addCapability(SPIRV::Capability::LongCompositesINTEL);
2408 break;
2409 }
2410 case SPIRV::OpArbitraryFloatEQALTERA:
2411 case SPIRV::OpArbitraryFloatGEALTERA:
2412 case SPIRV::OpArbitraryFloatGTALTERA:
2413 case SPIRV::OpArbitraryFloatLEALTERA:
2414 case SPIRV::OpArbitraryFloatLTALTERA:
2415 case SPIRV::OpArbitraryFloatCbrtALTERA:
2416 case SPIRV::OpArbitraryFloatCosALTERA:
2417 case SPIRV::OpArbitraryFloatCosPiALTERA:
2418 case SPIRV::OpArbitraryFloatExp10ALTERA:
2419 case SPIRV::OpArbitraryFloatExp2ALTERA:
2420 case SPIRV::OpArbitraryFloatExpALTERA:
2421 case SPIRV::OpArbitraryFloatExpm1ALTERA:
2422 case SPIRV::OpArbitraryFloatHypotALTERA:
2423 case SPIRV::OpArbitraryFloatLog10ALTERA:
2424 case SPIRV::OpArbitraryFloatLog1pALTERA:
2425 case SPIRV::OpArbitraryFloatLog2ALTERA:
2426 case SPIRV::OpArbitraryFloatLogALTERA:
2427 case SPIRV::OpArbitraryFloatRecipALTERA:
2428 case SPIRV::OpArbitraryFloatSinCosALTERA:
2429 case SPIRV::OpArbitraryFloatSinCosPiALTERA:
2430 case SPIRV::OpArbitraryFloatSinALTERA:
2431 case SPIRV::OpArbitraryFloatSinPiALTERA:
2432 case SPIRV::OpArbitraryFloatSqrtALTERA:
2433 case SPIRV::OpArbitraryFloatACosALTERA:
2434 case SPIRV::OpArbitraryFloatACosPiALTERA:
2435 case SPIRV::OpArbitraryFloatAddALTERA:
2436 case SPIRV::OpArbitraryFloatASinALTERA:
2437 case SPIRV::OpArbitraryFloatASinPiALTERA:
2438 case SPIRV::OpArbitraryFloatATan2ALTERA:
2439 case SPIRV::OpArbitraryFloatATanALTERA:
2440 case SPIRV::OpArbitraryFloatATanPiALTERA:
2441 case SPIRV::OpArbitraryFloatCastFromIntALTERA:
2442 case SPIRV::OpArbitraryFloatCastALTERA:
2443 case SPIRV::OpArbitraryFloatCastToIntALTERA:
2444 case SPIRV::OpArbitraryFloatDivALTERA:
2445 case SPIRV::OpArbitraryFloatMulALTERA:
2446 case SPIRV::OpArbitraryFloatPowALTERA:
2447 case SPIRV::OpArbitraryFloatPowNALTERA:
2448 case SPIRV::OpArbitraryFloatPowRALTERA:
2449 case SPIRV::OpArbitraryFloatRSqrtALTERA:
2450 case SPIRV::OpArbitraryFloatSubALTERA: {
2451 if (!ST.canUseExtension(
2452 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_floating_point))
2454 "Floating point instructions can't be translated correctly without "
2455 "enabled SPV_ALTERA_arbitrary_precision_floating_point extension!",
2456 false);
2457 Reqs.addExtension(
2458 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_floating_point);
2459 Reqs.addCapability(
2460 SPIRV::Capability::ArbitraryPrecisionFloatingPointALTERA);
2461 break;
2462 }
2463 case SPIRV::OpSubgroupMatrixMultiplyAccumulateINTEL: {
2464 if (!ST.canUseExtension(
2465 SPIRV::Extension::SPV_INTEL_subgroup_matrix_multiply_accumulate))
2467 "OpSubgroupMatrixMultiplyAccumulateINTEL instruction requires the "
2468 "following SPIR-V "
2469 "extension: SPV_INTEL_subgroup_matrix_multiply_accumulate",
2470 false);
2471 Reqs.addExtension(
2472 SPIRV::Extension::SPV_INTEL_subgroup_matrix_multiply_accumulate);
2473 Reqs.addCapability(
2474 SPIRV::Capability::SubgroupMatrixMultiplyAccumulateINTEL);
2475 break;
2476 }
2477 case SPIRV::OpBitwiseFunctionINTEL: {
2478 if (!ST.canUseExtension(
2479 SPIRV::Extension::SPV_INTEL_ternary_bitwise_function))
2481 "OpBitwiseFunctionINTEL instruction requires the following SPIR-V "
2482 "extension: SPV_INTEL_ternary_bitwise_function",
2483 false);
2484 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_ternary_bitwise_function);
2485 Reqs.addCapability(SPIRV::Capability::TernaryBitwiseFunctionINTEL);
2486 break;
2487 }
2488 case SPIRV::OpCopyMemorySized: {
2489 Reqs.addCapability(SPIRV::Capability::Addresses);
2490 // TODO: Add UntypedPointersKHR when implemented.
2491 break;
2492 }
2493 case SPIRV::OpPredicatedLoadINTEL:
2494 case SPIRV::OpPredicatedStoreINTEL: {
2495 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_predicated_io))
2497 "OpPredicated[Load/Store]INTEL instructions require "
2498 "the following SPIR-V extension: SPV_INTEL_predicated_io",
2499 false);
2500 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_predicated_io);
2501 Reqs.addCapability(SPIRV::Capability::PredicatedIOINTEL);
2502 break;
2503 }
2504 case SPIRV::OpFAddS:
2505 case SPIRV::OpFSubS:
2506 case SPIRV::OpFMulS:
2507 case SPIRV::OpFDivS:
2508 case SPIRV::OpFRemS:
2509 case SPIRV::OpFMod:
2510 case SPIRV::OpFNegate:
2511 case SPIRV::OpFAddV:
2512 case SPIRV::OpFSubV:
2513 case SPIRV::OpFMulV:
2514 case SPIRV::OpFDivV:
2515 case SPIRV::OpFRemV:
2516 case SPIRV::OpFNegateV: {
2517 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
2518 SPIRVTypeInst TypeDef = MRI.getVRegDef(MI.getOperand(1).getReg());
2519 if (TypeDef->getOpcode() == SPIRV::OpTypeVector)
2520 TypeDef = MRI.getVRegDef(TypeDef->getOperand(1).getReg());
2521 if (isBFloat16Type(TypeDef)) {
2522 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic))
2524 "Arithmetic instructions with bfloat16 arguments require the "
2525 "following SPIR-V extension: SPV_INTEL_bfloat16_arithmetic",
2526 false);
2527 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic);
2528 Reqs.addCapability(SPIRV::Capability::BFloat16ArithmeticINTEL);
2529 }
2530 break;
2531 }
2532 case SPIRV::OpOrdered:
2533 case SPIRV::OpUnordered:
2534 case SPIRV::OpFOrdEqual:
2535 case SPIRV::OpFOrdNotEqual:
2536 case SPIRV::OpFOrdLessThan:
2537 case SPIRV::OpFOrdLessThanEqual:
2538 case SPIRV::OpFOrdGreaterThan:
2539 case SPIRV::OpFOrdGreaterThanEqual:
2540 case SPIRV::OpFUnordEqual:
2541 case SPIRV::OpFUnordNotEqual:
2542 case SPIRV::OpFUnordLessThan:
2543 case SPIRV::OpFUnordLessThanEqual:
2544 case SPIRV::OpFUnordGreaterThan:
2545 case SPIRV::OpFUnordGreaterThanEqual: {
2546 const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
2547 MachineInstr *OperandDef = MRI.getVRegDef(MI.getOperand(2).getReg());
2548 SPIRVTypeInst TypeDef = MRI.getVRegDef(OperandDef->getOperand(1).getReg());
2549 if (TypeDef->getOpcode() == SPIRV::OpTypeVector)
2550 TypeDef = MRI.getVRegDef(TypeDef->getOperand(1).getReg());
2551 if (isBFloat16Type(TypeDef)) {
2552 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic))
2554 "Relational instructions with bfloat16 arguments require the "
2555 "following SPIR-V extension: SPV_INTEL_bfloat16_arithmetic",
2556 false);
2557 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bfloat16_arithmetic);
2558 Reqs.addCapability(SPIRV::Capability::BFloat16ArithmeticINTEL);
2559 }
2560 break;
2561 }
2562 case SPIRV::OpDPdxCoarse:
2563 case SPIRV::OpDPdyCoarse:
2564 case SPIRV::OpDPdxFine:
2565 case SPIRV::OpDPdyFine: {
2566 Reqs.addCapability(SPIRV::Capability::DerivativeControl);
2567 break;
2568 }
2569 case SPIRV::OpLoopControlINTEL: {
2570 Reqs.addExtension(SPIRV::Extension::SPV_INTEL_unstructured_loop_controls);
2571 Reqs.addCapability(SPIRV::Capability::UnstructuredLoopControlsINTEL);
2572 break;
2573 }
2574
2575 default:
2576 break;
2577 }
2578
2579 // If we require capability Shader, then we can remove the requirement for
2580 // the BitInstructions capability, since Shader is a superset capability
2581 // of BitInstructions.
2582 Reqs.removeCapabilityIf(SPIRV::Capability::BitInstructions,
2583 SPIRV::Capability::Shader);
2584}
2585
2586static void collectReqs(const Module &M, SPIRV::ModuleAnalysisInfo &MAI,
2587 MachineModuleInfo *MMI, const SPIRVSubtarget &ST) {
2588 // Collect requirements for existing instructions.
2589 for (const Function &F : M) {
2591 if (!MF)
2592 continue;
2593 for (const MachineBasicBlock &MBB : *MF)
2594 for (const MachineInstr &MI : MBB)
2595 addInstrRequirements(MI, MAI, ST);
2596 }
2597 // Collect requirements for OpExecutionMode instructions.
2598 auto Node = M.getNamedMetadata("spirv.ExecutionMode");
2599 if (Node) {
2600 bool RequireFloatControls = false, RequireIntelFloatControls2 = false,
2601 RequireKHRFloatControls2 = false,
2602 VerLower14 = !ST.isAtLeastSPIRVVer(VersionTuple(1, 4));
2603 bool HasIntelFloatControls2 =
2604 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_float_controls2);
2605 bool HasKHRFloatControls2 =
2606 ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2);
2607 for (unsigned i = 0; i < Node->getNumOperands(); i++) {
2608 MDNode *MDN = cast<MDNode>(Node->getOperand(i));
2609 const MDOperand &MDOp = MDN->getOperand(1);
2610 if (auto *CMeta = dyn_cast<ConstantAsMetadata>(MDOp)) {
2611 Constant *C = CMeta->getValue();
2612 if (ConstantInt *Const = dyn_cast<ConstantInt>(C)) {
2613 auto EM = Const->getZExtValue();
2614 // SPV_KHR_float_controls is not available until v1.4:
2615 // add SPV_KHR_float_controls if the version is too low
2616 switch (EM) {
2617 case SPIRV::ExecutionMode::DenormPreserve:
2618 case SPIRV::ExecutionMode::DenormFlushToZero:
2619 case SPIRV::ExecutionMode::RoundingModeRTE:
2620 case SPIRV::ExecutionMode::RoundingModeRTZ:
2621 RequireFloatControls = VerLower14;
2623 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2624 break;
2625 case SPIRV::ExecutionMode::RoundingModeRTPINTEL:
2626 case SPIRV::ExecutionMode::RoundingModeRTNINTEL:
2627 case SPIRV::ExecutionMode::FloatingPointModeALTINTEL:
2628 case SPIRV::ExecutionMode::FloatingPointModeIEEEINTEL:
2629 if (HasIntelFloatControls2) {
2630 RequireIntelFloatControls2 = true;
2632 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2633 }
2634 break;
2635 case SPIRV::ExecutionMode::FPFastMathDefault: {
2636 if (HasKHRFloatControls2) {
2637 RequireKHRFloatControls2 = true;
2639 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2640 }
2641 break;
2642 }
2643 case SPIRV::ExecutionMode::ContractionOff:
2644 case SPIRV::ExecutionMode::SignedZeroInfNanPreserve:
2645 if (HasKHRFloatControls2) {
2646 RequireKHRFloatControls2 = true;
2648 SPIRV::OperandCategory::ExecutionModeOperand,
2649 SPIRV::ExecutionMode::FPFastMathDefault, ST);
2650 } else {
2652 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2653 }
2654 break;
2655 default:
2657 SPIRV::OperandCategory::ExecutionModeOperand, EM, ST);
2658 }
2659 }
2660 }
2661 }
2662 if (RequireFloatControls &&
2663 ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls))
2664 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls);
2665 if (RequireIntelFloatControls2)
2666 MAI.Reqs.addExtension(SPIRV::Extension::SPV_INTEL_float_controls2);
2667 if (RequireKHRFloatControls2)
2668 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_float_controls2);
2669 }
2670 for (const Function &F : M) {
2671 if (F.isDeclaration())
2672 continue;
2673 if (F.getMetadata("reqd_work_group_size"))
2675 SPIRV::OperandCategory::ExecutionModeOperand,
2676 SPIRV::ExecutionMode::LocalSize, ST);
2677 if (F.getFnAttribute("hlsl.numthreads").isValid()) {
2679 SPIRV::OperandCategory::ExecutionModeOperand,
2680 SPIRV::ExecutionMode::LocalSize, ST);
2681 }
2682 if (F.getFnAttribute("enable-maximal-reconvergence").getValueAsBool()) {
2683 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_maximal_reconvergence);
2684 }
2685 if (F.getMetadata("work_group_size_hint"))
2687 SPIRV::OperandCategory::ExecutionModeOperand,
2688 SPIRV::ExecutionMode::LocalSizeHint, ST);
2689 if (F.getMetadata("intel_reqd_sub_group_size") ||
2690 F.getMetadata("reqd_sub_group_size"))
2692 SPIRV::OperandCategory::ExecutionModeOperand,
2693 SPIRV::ExecutionMode::SubgroupSize, ST);
2694 if (F.getMetadata("max_work_group_size"))
2696 SPIRV::OperandCategory::ExecutionModeOperand,
2697 SPIRV::ExecutionMode::MaxWorkgroupSizeINTEL, ST);
2698 if (F.getMetadata("vec_type_hint"))
2700 SPIRV::OperandCategory::ExecutionModeOperand,
2701 SPIRV::ExecutionMode::VecTypeHint, ST);
2702
2703 if (F.hasOptNone()) {
2704 if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_optnone)) {
2705 MAI.Reqs.addExtension(SPIRV::Extension::SPV_INTEL_optnone);
2706 MAI.Reqs.addCapability(SPIRV::Capability::OptNoneINTEL);
2707 } else if (ST.canUseExtension(SPIRV::Extension::SPV_EXT_optnone)) {
2708 MAI.Reqs.addExtension(SPIRV::Extension::SPV_EXT_optnone);
2709 MAI.Reqs.addCapability(SPIRV::Capability::OptNoneEXT);
2710 }
2711 }
2712 }
2713}
2714
2715static unsigned getFastMathFlags(const MachineInstr &I,
2716 const SPIRVSubtarget &ST) {
2717 unsigned Flags = SPIRV::FPFastMathMode::None;
2718 bool CanUseKHRFloatControls2 =
2719 ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2);
2720 if (I.getFlag(MachineInstr::MIFlag::FmNoNans))
2721 Flags |= SPIRV::FPFastMathMode::NotNaN;
2722 if (I.getFlag(MachineInstr::MIFlag::FmNoInfs))
2723 Flags |= SPIRV::FPFastMathMode::NotInf;
2724 if (I.getFlag(MachineInstr::MIFlag::FmNsz))
2725 Flags |= SPIRV::FPFastMathMode::NSZ;
2726 if (I.getFlag(MachineInstr::MIFlag::FmArcp))
2727 Flags |= SPIRV::FPFastMathMode::AllowRecip;
2728 if (I.getFlag(MachineInstr::MIFlag::FmContract) && CanUseKHRFloatControls2)
2729 Flags |= SPIRV::FPFastMathMode::AllowContract;
2730 if (I.getFlag(MachineInstr::MIFlag::FmReassoc)) {
2731 if (CanUseKHRFloatControls2)
2732 // LLVM reassoc maps to SPIRV transform, see
2733 // https://github.com/KhronosGroup/SPIRV-Registry/issues/326 for details.
2734 // Because we are enabling AllowTransform, we must enable AllowReassoc and
2735 // AllowContract too, as required by SPIRV spec. Also, we used to map
2736 // MIFlag::FmReassoc to FPFastMathMode::Fast, which now should instead by
2737 // replaced by turning all the other bits instead. Therefore, we're
2738 // enabling every bit here except None and Fast.
2739 Flags |= SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
2740 SPIRV::FPFastMathMode::NSZ | SPIRV::FPFastMathMode::AllowRecip |
2741 SPIRV::FPFastMathMode::AllowTransform |
2742 SPIRV::FPFastMathMode::AllowReassoc |
2743 SPIRV::FPFastMathMode::AllowContract;
2744 else
2745 Flags |= SPIRV::FPFastMathMode::Fast;
2746 }
2747
2748 if (CanUseKHRFloatControls2) {
2749 // Error out if SPIRV::FPFastMathMode::Fast is enabled.
2750 assert(!(Flags & SPIRV::FPFastMathMode::Fast) &&
2751 "SPIRV::FPFastMathMode::Fast is deprecated and should not be used "
2752 "anymore.");
2753
2754 // Error out if AllowTransform is enabled without AllowReassoc and
2755 // AllowContract.
2756 assert((!(Flags & SPIRV::FPFastMathMode::AllowTransform) ||
2757 ((Flags & SPIRV::FPFastMathMode::AllowReassoc &&
2758 Flags & SPIRV::FPFastMathMode::AllowContract))) &&
2759 "SPIRV::FPFastMathMode::AllowTransform requires AllowReassoc and "
2760 "AllowContract flags to be enabled as well.");
2761 }
2762
2763 return Flags;
2764}
2765
2766static bool isFastMathModeAvailable(const SPIRVSubtarget &ST) {
2767 if (ST.isKernel())
2768 return true;
2769 if (ST.getSPIRVVersion() < VersionTuple(1, 2))
2770 return false;
2771 return ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2);
2772}
2773
2774static void handleMIFlagDecoration(
2775 MachineInstr &I, const SPIRVSubtarget &ST, const SPIRVInstrInfo &TII,
2777 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec) {
2778 if (TII.canUseIntegerWrapDecoration(I)) {
2779 if (I.getFlag(MachineInstr::MIFlag::NoSWrap) &&
2780 getSymbolicOperandRequirements(
2781 SPIRV::OperandCategory::DecorationOperand,
2782 SPIRV::Decoration::NoSignedWrap, ST, Reqs)
2783 .IsSatisfiable)
2784 buildOpDecorate(I.getOperand(0).getReg(), I, TII,
2785 SPIRV::Decoration::NoSignedWrap, {});
2786 if (I.getFlag(MachineInstr::MIFlag::NoUWrap) &&
2787 getSymbolicOperandRequirements(
2788 SPIRV::OperandCategory::DecorationOperand,
2789 SPIRV::Decoration::NoUnsignedWrap, ST, Reqs)
2790 .IsSatisfiable)
2791 buildOpDecorate(I.getOperand(0).getReg(), I, TII,
2792 SPIRV::Decoration::NoUnsignedWrap, {});
2793 }
2794 // In Kernel environments, FPFastMathMode on OpExtInst is valid per core
2795 // spec. For other instruction types, SPV_KHR_float_controls2 is required.
2796 bool CanUseFM =
2797 TII.canUseFastMathFlags(
2798 I, ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2)) ||
2799 (ST.isKernel() && I.getOpcode() == SPIRV::OpExtInst);
2800 if (!CanUseFM)
2801 return;
2802
2803 unsigned FMFlags = getFastMathFlags(I, ST);
2804 if (FMFlags == SPIRV::FPFastMathMode::None) {
2805 // We also need to check if any FPFastMathDefault info was set for the
2806 // types used in this instruction.
2807 if (FPFastMathDefaultInfoVec.empty())
2808 return;
2809
2810 // There are three types of instructions that can use fast math flags:
2811 // 1. Arithmetic instructions (FAdd, FMul, FSub, FDiv, FRem, etc.)
2812 // 2. Relational instructions (FCmp, FOrd, FUnord, etc.)
2813 // 3. Extended instructions (ExtInst)
2814 // For arithmetic instructions, the floating point type can be in the
2815 // result type or in the operands, but they all must be the same.
2816 // For the relational and logical instructions, the floating point type
2817 // can only be in the operands 1 and 2, not the result type. Also, the
2818 // operands must have the same type. For the extended instructions, the
2819 // floating point type can be in the result type or in the operands. It's
2820 // unclear if the operands and the result type must be the same. Let's
2821 // assume they must be. Therefore, for 1. and 2., we can check the first
2822 // operand type, and for 3. we can check the result type.
2823 assert(I.getNumOperands() >= 3 && "Expected at least 3 operands");
2824 Register ResReg = I.getOpcode() == SPIRV::OpExtInst
2825 ? I.getOperand(1).getReg()
2826 : I.getOperand(2).getReg();
2827 SPIRVTypeInst ResType = GR->getSPIRVTypeForVReg(ResReg, I.getMF());
2828 const Type *Ty = GR->getTypeForSPIRVType(ResType);
2829 Ty = Ty->isVectorTy() ? cast<VectorType>(Ty)->getElementType() : Ty;
2830
2831 // Match instruction type with the FPFastMathDefaultInfoVec.
2832 bool Emit = false;
2833 for (SPIRV::FPFastMathDefaultInfo &Elem : FPFastMathDefaultInfoVec) {
2834 if (Ty == Elem.Ty) {
2835 FMFlags = Elem.FastMathFlags;
2836 Emit = Elem.ContractionOff || Elem.SignedZeroInfNanPreserve ||
2837 Elem.FPFastMathDefault;
2838 break;
2839 }
2840 }
2841
2842 if (FMFlags == SPIRV::FPFastMathMode::None && !Emit)
2843 return;
2844 }
2845 if (isFastMathModeAvailable(ST)) {
2846 Register DstReg = I.getOperand(0).getReg();
2847 buildOpDecorate(DstReg, I, TII, SPIRV::Decoration::FPFastMathMode,
2848 {FMFlags});
2849 }
2850}
2851
2852// Walk all functions and add decorations related to MI flags.
2853static void addDecorations(const Module &M, const SPIRVInstrInfo &TII,
2854 MachineModuleInfo *MMI, const SPIRVSubtarget &ST,
2856 const SPIRVGlobalRegistry *GR) {
2857 for (const Function &F : M) {
2859 if (!MF)
2860 continue;
2861
2862 for (auto &MBB : *MF)
2863 for (auto &MI : MBB)
2864 handleMIFlagDecoration(MI, ST, TII, MAI.Reqs, GR,
2866 }
2867}
2868
2869static void addMBBNames(const Module &M, const SPIRVInstrInfo &TII,
2870 MachineModuleInfo *MMI, const SPIRVSubtarget &ST,
2872 for (const Function &F : M) {
2874 if (!MF)
2875 continue;
2876 if (MF->getFunction()
2878 .isValid())
2879 continue;
2880 MachineRegisterInfo &MRI = MF->getRegInfo();
2881 for (auto &MBB : *MF) {
2882 if (!MBB.hasName() || MBB.empty())
2883 continue;
2884 // Emit basic block names.
2886 MRI.setRegClass(Reg, &SPIRV::IDRegClass);
2887 buildOpName(Reg, MBB.getName(), *std::prev(MBB.end()), TII);
2888 MCRegister GlobalReg = MAI.getOrCreateMBBRegister(MBB);
2889 MAI.setRegisterAlias(MF, Reg, GlobalReg);
2890 }
2891 }
2892}
2893
2894// patching Instruction::PHI to SPIRV::OpPhi
2895static void patchPhis(const Module &M, SPIRVGlobalRegistry *GR,
2896 const SPIRVInstrInfo &TII, MachineModuleInfo *MMI) {
2897 for (const Function &F : M) {
2899 if (!MF)
2900 continue;
2901 for (auto &MBB : *MF) {
2902 for (MachineInstr &MI : MBB.phis()) {
2903 MI.setDesc(TII.get(SPIRV::OpPhi));
2904 Register ResTypeReg = GR->getSPIRVTypeID(
2905 GR->getSPIRVTypeForVReg(MI.getOperand(0).getReg(), MF));
2906 MI.insert(MI.operands_begin() + 1,
2907 {MachineOperand::CreateReg(ResTypeReg, false)});
2908 }
2909 }
2910
2911 MF->getProperties().setNoPHIs();
2912 }
2913}
2914
2916 const Module &M, SPIRV::ModuleAnalysisInfo &MAI, const Function *F) {
2917 auto it = MAI.FPFastMathDefaultInfoMap.find(F);
2918 if (it != MAI.FPFastMathDefaultInfoMap.end())
2919 return it->second;
2920
2921 // If the map does not contain the entry, create a new one. Initialize it to
2922 // contain all 3 elements sorted by bit width of target type: {half, float,
2923 // double}.
2924 SPIRV::FPFastMathDefaultInfoVector FPFastMathDefaultInfoVec;
2925 FPFastMathDefaultInfoVec.emplace_back(Type::getHalfTy(M.getContext()),
2926 SPIRV::FPFastMathMode::None);
2927 FPFastMathDefaultInfoVec.emplace_back(Type::getFloatTy(M.getContext()),
2928 SPIRV::FPFastMathMode::None);
2929 FPFastMathDefaultInfoVec.emplace_back(Type::getDoubleTy(M.getContext()),
2930 SPIRV::FPFastMathMode::None);
2931 return MAI.FPFastMathDefaultInfoMap[F] = std::move(FPFastMathDefaultInfoVec);
2932}
2933
2935 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec,
2936 const Type *Ty) {
2937 size_t BitWidth = Ty->getScalarSizeInBits();
2938 int Index =
2940 BitWidth);
2941 assert(Index >= 0 && Index < 3 &&
2942 "Expected FPFastMathDefaultInfo for half, float, or double");
2943 assert(FPFastMathDefaultInfoVec.size() == 3 &&
2944 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
2945 return FPFastMathDefaultInfoVec[Index];
2946}
2947
2948static void collectFPFastMathDefaults(const Module &M,
2950 const SPIRVSubtarget &ST) {
2951 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2))
2952 return;
2953
2954 // Store the FPFastMathDefaultInfo in the FPFastMathDefaultInfoMap.
2955 // We need the entry point (function) as the key, and the target
2956 // type and flags as the value.
2957 // We also need to check ContractionOff and SignedZeroInfNanPreserve
2958 // execution modes, as they are now deprecated and must be replaced
2959 // with FPFastMathDefaultInfo.
2960 auto Node = M.getNamedMetadata("spirv.ExecutionMode");
2961 if (!Node)
2962 return;
2963
2964 for (unsigned i = 0; i < Node->getNumOperands(); i++) {
2965 MDNode *MDN = cast<MDNode>(Node->getOperand(i));
2966 assert(MDN->getNumOperands() >= 2 && "Expected at least 2 operands");
2967 const Function *F = cast<Function>(
2968 cast<ConstantAsMetadata>(MDN->getOperand(0))->getValue());
2969 const auto EM =
2971 cast<ConstantAsMetadata>(MDN->getOperand(1))->getValue())
2972 ->getZExtValue();
2973 if (EM == SPIRV::ExecutionMode::FPFastMathDefault) {
2974 assert(MDN->getNumOperands() == 4 &&
2975 "Expected 4 operands for FPFastMathDefault");
2976
2977 const Type *T = cast<ValueAsMetadata>(MDN->getOperand(2))->getType();
2978 unsigned Flags =
2980 cast<ConstantAsMetadata>(MDN->getOperand(3))->getValue())
2981 ->getZExtValue();
2982 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2985 getFPFastMathDefaultInfo(FPFastMathDefaultInfoVec, T);
2986 Info.FastMathFlags = Flags;
2987 Info.FPFastMathDefault = true;
2988 } else if (EM == SPIRV::ExecutionMode::ContractionOff) {
2989 assert(MDN->getNumOperands() == 2 &&
2990 "Expected no operands for ContractionOff");
2991
2992 // We need to save this info for every possible FP type, i.e. {half,
2993 // float, double, fp128}.
2994 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
2996 for (SPIRV::FPFastMathDefaultInfo &Info : FPFastMathDefaultInfoVec) {
2997 Info.ContractionOff = true;
2998 }
2999 } else if (EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve) {
3000 assert(MDN->getNumOperands() == 3 &&
3001 "Expected 1 operand for SignedZeroInfNanPreserve");
3002 unsigned TargetWidth =
3004 cast<ConstantAsMetadata>(MDN->getOperand(2))->getValue())
3005 ->getZExtValue();
3006 // We need to save this info only for the FP type with TargetWidth.
3007 SPIRV::FPFastMathDefaultInfoVector &FPFastMathDefaultInfoVec =
3011 assert(Index >= 0 && Index < 3 &&
3012 "Expected FPFastMathDefaultInfo for half, float, or double");
3013 assert(FPFastMathDefaultInfoVec.size() == 3 &&
3014 "Expected FPFastMathDefaultInfoVec to have exactly 3 elements");
3015 FPFastMathDefaultInfoVec[Index].SignedZeroInfNanPreserve = true;
3016 }
3017 }
3018}
3019
3021 AU.addRequired<TargetPassConfig>();
3022 AU.addRequired<MachineModuleInfoWrapperPass>();
3023}
3024
3026 SPIRVTargetMachine &TM =
3027 getAnalysis<TargetPassConfig>().getTM<SPIRVTargetMachine>();
3028 ST = TM.getSubtargetImpl();
3029 GR = ST->getSPIRVGlobalRegistry();
3030 TII = ST->getInstrInfo();
3031
3033
3034 setBaseInfo(M);
3035
3036 patchPhis(M, GR, *TII, MMI);
3037
3038 addMBBNames(M, *TII, MMI, *ST, MAI);
3039 collectFPFastMathDefaults(M, MAI, *ST);
3040 addDecorations(M, *TII, MMI, *ST, MAI, GR);
3041
3042 collectReqs(M, MAI, MMI, *ST);
3043
3044 // Process type/const/global var/func decl instructions, number their
3045 // destination registers from 0 to N, collect Extensions and Capabilities.
3046 collectDeclarations(M);
3047
3048 // Number rest of registers from N+1 onwards.
3049 numberRegistersGlobally(M);
3050
3051 // Collect OpName, OpEntryPoint, OpDecorate etc, process other instructions.
3052 processOtherInstrs(M);
3053
3054 // If there are no entry points, we need the Linkage capability.
3055 if (MAI.MS[SPIRV::MB_EntryPoints].empty())
3056 MAI.Reqs.addCapability(SPIRV::Capability::Linkage);
3057
3058 // Set maximum ID used.
3059 GR->setBound(MAI.MaxID);
3060
3061 return false;
3062}
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:540
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.
Value * RHS
Value * LHS
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:758
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:1426
unsigned getNumOperands() const
Return number of MDNode operands.
Definition Metadata.h:1432
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)
void stable_sort(R &&Range)
Definition STLExtras.h:2116
std::string getStringImm(const MachineInstr &MI, unsigned StartIndex)
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1739
hash_code hash_value(const FixedPointSemantics &Val)
ExtensionList getSymbolicOperandExtensions(SPIRV::OperandCategory::OperandCategory Category, uint32_t Value)
CapabilityList getSymbolicOperandCapabilities(SPIRV::OperandCategory::OperandCategory Category, uint32_t Value)
SmallVector< SPIRV::Extension::Extension, 8 > ExtensionList
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
SmallVector< size_t > InstrSignature
void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, SPIRV::Decoration::Decoration Dec, ArrayRef< uint32_t > DecArgs, StringRef StrImm)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
VersionTuple getSymbolicOperandMaxVersion(SPIRV::OperandCategory::OperandCategory Category, uint32_t Value)
void erase(Container &C, ValueType V)
Wrapper function to remove a value from a container:
Definition STLExtras.h:2200
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:1947
SmallVector< SPIRV::Capability::Capability, 8 > CapabilityList
std::set< InstrSignature > InstrTraces
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition Hashing.h: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:149
void setSkipEmission(const MachineInstr *MI)
MCRegister getRegisterAlias(const MachineFunction *MF, Register Reg)
MCRegister getOrCreateMBBRegister(const MachineBasicBlock &MBB)
InstrList MS[NUM_MODULE_SECTIONS]
AddressingModel::AddressingModel Addr
void setRegisterAlias(const MachineFunction *MF, Register Reg, MCRegister AliasReg)
DenseMap< const Function *, SPIRV::FPFastMathDefaultInfoVector > FPFastMathDefaultInfoMap
void addCapabilities(const CapabilityList &ToAdd)
bool isCapabilityAvailable(Capability::Capability Cap) const
void checkSatisfiable(const SPIRVSubtarget &ST) const
void getAndAddRequirements(SPIRV::OperandCategory::OperandCategory Category, uint32_t i, const SPIRVSubtarget &ST)
void addExtension(Extension::Extension ToAdd)
void initAvailableCapabilities(const SPIRVSubtarget &ST)
void removeCapabilityIf(const Capability::Capability ToRemove, const Capability::Capability IfPresent)
void addCapability(Capability::Capability ToAdd)
void addAvailableCaps(const CapabilityList &ToAdd)
void addRequirements(const Requirements &Req)
const std::optional< Capability::Capability > Cap