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