Thanks to visit codestin.com
Credit goes to llvm.org

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