LLVM 24.0.0git
SPIRVAsmPrinter.cpp
Go to the documentation of this file.
1//===-- SPIRVAsmPrinter.cpp - SPIR-V LLVM assembly writer ------*- 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// This file contains a printer that converts from our internal representation
10// of machine-dependent LLVM code to the SPIR-V assembly language.
11//
12//===----------------------------------------------------------------------===//
13
15#include "SPIRV.h"
16#include "SPIRVAuxDataHandler.h"
17#include "SPIRVInstrInfo.h"
18#include "SPIRVMCInstLower.h"
19#include "SPIRVModuleAnalysis.h"
21#include "SPIRVSubtarget.h"
22#include "SPIRVTargetMachine.h"
23#include "SPIRVUtils.h"
25#include "llvm/ADT/DenseMap.h"
32#include "llvm/MC/MCAsmInfo.h"
33#include "llvm/MC/MCAssembler.h"
34#include "llvm/MC/MCInst.h"
37#include "llvm/MC/MCStreamer.h"
38#include "llvm/MC/MCSymbol.h"
43
44using namespace llvm;
45
46#define DEBUG_TYPE "asm-printer"
47
48namespace {
49enum class SPIRVFPContractMode { On, Off, Fast };
50
51static cl::opt<SPIRVFPContractMode> SPIRVFPContract(
52 "spirv-fp-contract",
53 cl::desc("Override FP contraction policy for SPIR-V kernel entry points"),
55 clEnumValN(SPIRVFPContractMode::On, "on",
56 "Follow IR metadata (default)"),
57 clEnumValN(SPIRVFPContractMode::Off, "off",
58 "Force ContractionOff on all kernel entry points"),
59 clEnumValN(SPIRVFPContractMode::Fast, "fast",
60 "Suppress ContractionOff on all kernel entry points")),
61 cl::init(SPIRVFPContractMode::On));
62
63class SPIRVAsmPrinter : public AsmPrinter {
64 unsigned NLabels = 0;
66
67public:
68 explicit SPIRVAsmPrinter(TargetMachine &TM,
69 std::unique_ptr<MCStreamer> Streamer)
70 : AsmPrinter(TM, std::move(Streamer), ID), ModuleSectionsEmitted(false),
71 ST(nullptr), TII(nullptr), MAI(nullptr) {}
72 static char ID;
73 bool ModuleSectionsEmitted;
74 const SPIRVSubtarget *ST;
75 const SPIRVInstrInfo *TII;
76
77 StringRef getPassName() const override { return "SPIRV Assembly Printer"; }
78 void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O);
79 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
80 const char *ExtraCode, raw_ostream &O) override;
81
82 void outputMCInst(MCInst &Inst);
83 void outputInstruction(const MachineInstr *MI);
84 void outputModuleSection(SPIRV::ModuleSectionType MSType);
85 void outputGlobalRequirements();
86 void outputEntryPoints();
87 void outputDebugSourceAndStrings(const Module &M);
88 void outputOpExtInstImports(const Module &M);
89 void outputOpMemoryModel();
90 void outputOpFunctionEnd();
91 void outputExtFuncDecls();
92 void outputExecutionModeFromMDNode(MCRegister Reg, MDNode *Node,
93 SPIRV::ExecutionMode::ExecutionMode EM,
94 unsigned ExpectMDOps, int64_t DefVal);
95 void outputExecutionModeFromNumthreadsAttribute(
96 const MCRegister &Reg, const Attribute &Attr,
97 SPIRV::ExecutionMode::ExecutionMode EM);
98 void outputExecutionModeFromEnableMaximalReconvergenceAttr(
99 const MCRegister &Reg, const SPIRVSubtarget &ST);
100 void emitSimpleExecutionMode(MCRegister Reg,
101 SPIRV::ExecutionMode::ExecutionMode EM);
102 void outputExecutionMode(const Module &M);
103 void outputAnnotations(const Module &M);
104 void outputModuleSections();
105 void outputFPFastMathDefaultInfo();
106 bool isHidden() {
107 return MF->getFunction()
108 .getFnAttribute(SPIRV_BACKEND_SERVICE_FUN_NAME)
109 .isValid();
110 }
111
112 void emitInstruction(const MachineInstr *MI) override;
113 void emitFunctionEntryLabel() override {}
114 void emitFunctionHeader() override;
115 void emitFunctionBodyStart() override {}
116 void emitFunctionBodyEnd() override;
117 void emitBasicBlockStart(const MachineBasicBlock &MBB) override;
118 void emitBasicBlockEnd(const MachineBasicBlock &MBB) override {}
119 void emitGlobalVariable(const GlobalVariable *GV) override {}
120 void emitOpLabel(const MachineBasicBlock &MBB);
121 void emitEndOfAsmFile(Module &M) override;
122 bool doInitialization(Module &M) override;
123
124 void getAnalysisUsage(AnalysisUsage &AU) const override;
126
127 // Non-owning pointer to the NSDI handler registered via addAsmPrinterHandler.
128 // The handler's lifetime is managed by AsmPrinter (the base class of this
129 // object), so this pointer cannot dangle.
130 SPIRVNonSemanticDebugHandler *NSDebugHandler = nullptr;
131
132 std::unique_ptr<SPIRVAuxDataHandler> AuxDataHandler;
133
134protected:
135 void cleanUp(Module &M);
136};
137} // namespace
138
139void SPIRVAsmPrinter::getAnalysisUsage(AnalysisUsage &AU) const {
140 AU.addRequired<SPIRVModuleAnalysis>();
141 AU.addPreserved<SPIRVModuleAnalysis>();
143}
144
145// If the module has no functions, we need output global info anyway.
146void SPIRVAsmPrinter::emitEndOfAsmFile(Module &M) {
147 if (!ModuleSectionsEmitted) {
148 outputModuleSections();
149 ModuleSectionsEmitted = true;
150 }
151
152 ST = static_cast<const SPIRVTargetMachine &>(TM).getSubtargetImpl();
153 // SPIRVModuleAnalysis sets GR->Bound = MAI->MaxID before printing. Any IDs
154 // allocated by AsmPrinter handlers (e.g. SPIRVNonSemanticDebugHandler) during
155 // outputModuleSections() are not counted. Refresh the bound here so the
156 // formula below sees the final allocation count.
157 if (MAI)
158 ST->getSPIRVGlobalRegistry()->setBound(MAI->MaxID);
159 VersionTuple SPIRVVersion = ST->getSPIRVVersion();
160 uint32_t Major = SPIRVVersion.getMajor();
161 uint32_t Minor = SPIRVVersion.getMinor().value_or(0);
162 // Bound is an approximation that accounts for the maximum used register
163 // number and number of generated OpLabels
164 unsigned Bound = 2 * (ST->getBound() + 1) + NLabels;
165 if (MCAssembler *Asm = OutStreamer->getAssemblerPtr())
166 static_cast<SPIRVObjectWriter &>(Asm->getWriter())
167 .setBuildVersion(Major, Minor, Bound);
168
169 cleanUp(M);
170}
171
172// Any cleanup actions with the Module after we don't care about its content
173// anymore.
174void SPIRVAsmPrinter::cleanUp(Module &M) {
175 // Verifier disallows uses of intrinsic global variables.
176 for (StringRef GVName :
177 {"llvm.global_ctors", "llvm.global_dtors", "llvm.used"}) {
178 if (GlobalVariable *GV = M.getNamedGlobal(GVName))
179 GV->setName("");
180 }
181}
182
183void SPIRVAsmPrinter::emitFunctionHeader() {
184 if (!ModuleSectionsEmitted) {
185 outputModuleSections();
186 ModuleSectionsEmitted = true;
187 }
188 // Get the subtarget from the current MachineFunction.
189 ST = &MF->getSubtarget<SPIRVSubtarget>();
190 TII = ST->getInstrInfo();
191 const Function &F = MF->getFunction();
192
193 if (isVerbose() && !isHidden()) {
194 OutStreamer->getCommentOS()
195 << "-- Begin function "
196 << GlobalValue::dropLLVMManglingEscape(F.getName()) << '\n';
197 }
198
199 auto Section = getObjFileLowering().SectionForGlobal(&F, TM);
200 MF->setSection(Section);
201
202 // SPIRVAsmPrinter::emitFunctionHeader() does not call the base class,
203 // so handlers never receive beginFunction() from the normal path. Drive the
204 // per-function lifecycle here, matching what AsmPrinter::emitFunctionHeader()
205 // does for other targets.
206 for (auto &Handler : Handlers) {
207 Handler->beginFunction(MF);
208 Handler->beginBasicBlockSection(MF->front());
209 }
210}
211
212void SPIRVAsmPrinter::outputOpFunctionEnd() {
213 MCInst FunctionEndInst;
214 FunctionEndInst.setOpcode(SPIRV::OpFunctionEnd);
215 outputMCInst(FunctionEndInst);
216}
217
218void SPIRVAsmPrinter::emitFunctionBodyEnd() {
219 if (!isHidden())
220 outputOpFunctionEnd();
221}
222
223void SPIRVAsmPrinter::emitOpLabel(const MachineBasicBlock &MBB) {
224 // Do not emit anything if it's an internal service function.
225 if (isHidden())
226 return;
227
228 MCInst LabelInst;
229 LabelInst.setOpcode(SPIRV::OpLabel);
230 LabelInst.addOperand(MCOperand::createReg(MAI->getOrCreateMBBRegister(MBB)));
231 outputMCInst(LabelInst);
232 ++NLabels;
233 LabeledMBB.insert(&MBB);
234}
235
236void SPIRVAsmPrinter::emitBasicBlockStart(const MachineBasicBlock &MBB) {
237 // Do not emit anything if it's an internal service function.
238 if (MBB.empty() || isHidden())
239 return;
240
241 // If it's the first MBB in MF, it has OpFunction and OpFunctionParameter, so
242 // OpLabel should be output after them.
243 if (MBB.getNumber() == MF->front().getNumber()) {
244 for (const MachineInstr &MI : MBB)
245 if (MI.getOpcode() == SPIRV::OpFunction)
246 return;
247 // TODO: this case should be checked by the verifier.
248 report_fatal_error("OpFunction is expected in the front MBB of MF");
249 }
250 emitOpLabel(MBB);
251}
252
253void SPIRVAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
254 raw_ostream &O) {
255 const MachineOperand &MO = MI->getOperand(OpNum);
256
257 switch (MO.getType()) {
260 break;
261
263 O << MO.getImm();
264 break;
265
267 O << MO.getFPImm();
268 break;
269
271 O << *MO.getMBB()->getSymbol();
272 break;
273
275 O << *getSymbol(MO.getGlobal());
276 break;
277
279 MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress());
280 O << BA->getName();
281 break;
282 }
283
285 O << *GetExternalSymbolSymbol(MO.getSymbolName());
286 break;
287
290 default:
291 llvm_unreachable("<unknown operand type>");
292 }
293}
294
295bool SPIRVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
296 const char *ExtraCode, raw_ostream &O) {
297 if (ExtraCode && ExtraCode[0])
298 return true; // Invalid instruction - SPIR-V does not have special modifiers
299
300 printOperand(MI, OpNo, O);
301 return false;
302}
303
305 const SPIRVInstrInfo *TII) {
306 return TII->isHeaderInstr(*MI) || MI->getOpcode() == SPIRV::OpFunction ||
307 MI->getOpcode() == SPIRV::OpFunctionParameter;
308}
309
310void SPIRVAsmPrinter::outputMCInst(MCInst &Inst) {
311 OutStreamer->emitInstruction(Inst, *OutContext.getSubtargetInfo());
312}
313
314void SPIRVAsmPrinter::outputInstruction(const MachineInstr *MI) {
315 SPIRVMCInstLower MCInstLowering;
316 MCInst TmpInst;
317 MCInstLowering.lower(MI, TmpInst, MAI);
318 outputMCInst(TmpInst);
319}
320
321void SPIRVAsmPrinter::emitInstruction(const MachineInstr *MI) {
322 SPIRV_MC::verifyInstructionPredicates(MI->getOpcode(),
323 getSubtargetInfo().getFeatureBits());
324
325 bool InstructionEmitted = !MAI->getSkipEmission(MI);
326 if (InstructionEmitted)
327 outputInstruction(MI);
328
329 // Output OpLabel after OpFunction and OpFunctionParameter in the first MBB.
330 const MachineInstr *NextMI = MI->getNextNode();
331 bool BlockHasLabel = LabeledMBB.contains(MI->getParent());
332 bool IsFunctionPreambleInstruction = isFuncOrHeaderInstr(MI, TII);
333 bool IsNextInstructionFunctionPreamble =
334 NextMI && isFuncOrHeaderInstr(NextMI, TII);
335 bool ShouldEmitEntryLabel = !BlockHasLabel && IsFunctionPreambleInstruction &&
336 !IsNextInstructionFunctionPreamble;
337 if (ShouldEmitEntryLabel) {
338 assert(MI->getParent()->getNumber() == MF->front().getNumber() &&
339 "OpFunction is not in the front MBB of MF");
340 emitOpLabel(*MI->getParent());
341 if (NSDebugHandler && !isHidden())
342 NSDebugHandler->notifyEntryLabelEmitted(*MF);
343 }
344}
345
346void SPIRVAsmPrinter::outputModuleSection(SPIRV::ModuleSectionType MSType) {
347 for (const MachineInstr *MI : MAI->getMSInstrs(MSType))
348 outputInstruction(MI);
349}
350
351void SPIRVAsmPrinter::outputDebugSourceAndStrings(const Module &M) {
352 // Output OpSourceExtensions.
353 for (auto &Str : MAI->SrcExt) {
354 MCInst Inst;
355 Inst.setOpcode(SPIRV::OpSourceExtension);
356 addStringImm(Str.first(), Inst);
357 outputMCInst(Inst);
358 }
359 // Output OpString.
360 outputModuleSection(SPIRV::MB_DebugStrings);
361 // Output OpSource.
362 MCInst Inst;
363 Inst.setOpcode(SPIRV::OpSource);
364 Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(MAI->SrcLang)));
365 Inst.addOperand(
366 MCOperand::createImm(static_cast<unsigned>(MAI->SrcLangVersion)));
367 outputMCInst(Inst);
368 // Emit OpString instructions for NSDI file paths and type names here, in
369 // section 7. OpString must precede type/constant declarations per the SPIR-V
370 // module layout (section 2.4). The OpExtInst instructions that reference
371 // these strings are emitted later at section 10 by
372 // emitNonSemanticGlobalDebugInfo().
373 if (NSDebugHandler)
374 NSDebugHandler->emitNonSemanticDebugStrings(*MAI);
375 if (AuxDataHandler)
376 AuxDataHandler->emitAuxDataStrings(*MAI);
377}
378
379void SPIRVAsmPrinter::outputOpExtInstImports(const Module &M) {
380 for (auto &CU : MAI->ExtInstSetMap) {
381 unsigned Set = CU.first;
382 MCRegister Reg = CU.second;
383 MCInst Inst;
384 Inst.setOpcode(SPIRV::OpExtInstImport);
387 static_cast<SPIRV::InstructionSet::InstructionSet>(Set)),
388 Inst);
389 outputMCInst(Inst);
390 }
391}
392
393void SPIRVAsmPrinter::outputOpMemoryModel() {
394 MCInst Inst;
395 Inst.setOpcode(SPIRV::OpMemoryModel);
396 Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(MAI->Addr)));
397 Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(MAI->Mem)));
398 outputMCInst(Inst);
399}
400
401// Before the OpEntryPoints' output, we need to add the entry point's
402// interfaces. The interface is a list of IDs of global OpVariable instructions.
403// These declare the set of global variables from a module that form
404// the interface of this entry point.
405void SPIRVAsmPrinter::outputEntryPoints() {
406 // Find all OpVariable IDs with required StorageClass.
407 DenseSet<MCRegister> InterfaceIDs;
408 for (const MachineInstr *MI : MAI->GlobalVarList) {
409 assert(MI->getOpcode() == SPIRV::OpVariable ||
410 MI->getOpcode() == SPIRV::OpUntypedVariableKHR);
411 auto SC = static_cast<SPIRV::StorageClass::StorageClass>(
412 MI->getOperand(2).getImm());
413 // Before version 1.4, the interface's storage classes are limited to
414 // the Input and Output storage classes. Starting with version 1.4,
415 // the interface's storage classes are all storage classes used in
416 // declaring all global variables referenced by the entry point call tree.
417 if (ST->isAtLeastSPIRVVer(VersionTuple(1, 4)) ||
418 SC == SPIRV::StorageClass::Input || SC == SPIRV::StorageClass::Output) {
419 const MachineFunction *MF = MI->getMF();
420 MCRegister Reg = MAI->getRegisterAlias(MF, MI->getOperand(0).getReg());
421 InterfaceIDs.insert(Reg);
422 }
423 }
424
425 // Output OpEntryPoints adding interface args to all of them.
426 for (const MachineInstr *MI : MAI->getMSInstrs(SPIRV::MB_EntryPoints)) {
427 SPIRVMCInstLower MCInstLowering;
428 MCInst TmpInst;
429 MCInstLowering.lower(MI, TmpInst, MAI);
430 for (MCRegister Reg : InterfaceIDs) {
431 assert(Reg.isValid());
433 }
434 outputMCInst(TmpInst);
435 }
436}
437
438// Create global OpCapability instructions for the required capabilities.
439void SPIRVAsmPrinter::outputGlobalRequirements() {
440 // Abort here if not all requirements can be satisfied.
441 MAI->Reqs.checkSatisfiable(*ST);
442
443 for (const auto &Cap : MAI->Reqs.getMinimalCapabilities()) {
444 MCInst Inst;
445 Inst.setOpcode(SPIRV::OpCapability);
447 outputMCInst(Inst);
448 }
449
450 // Generate the final OpExtensions with strings instead of enums.
451 for (const auto &Ext : MAI->Reqs.getExtensions()) {
452 MCInst Inst;
453 Inst.setOpcode(SPIRV::OpExtension);
455 SPIRV::OperandCategory::ExtensionOperand, Ext),
456 Inst);
457 outputMCInst(Inst);
458 }
459 // TODO add a pseudo instr for version number.
460}
461
462void SPIRVAsmPrinter::outputExtFuncDecls() {
463 // Insert OpFunctionEnd after each declaration.
464 auto I = MAI->getMSInstrs(SPIRV::MB_ExtFuncDecls).begin(),
465 E = MAI->getMSInstrs(SPIRV::MB_ExtFuncDecls).end();
466 for (; I != E; ++I) {
467 outputInstruction(*I);
468 if ((I + 1) == E || (*(I + 1))->getOpcode() == SPIRV::OpFunction)
469 outputOpFunctionEnd();
470 }
471}
472
473// Encode LLVM type by SPIR-V execution mode VecTypeHint.
474static unsigned encodeVecTypeHint(Type *Ty) {
475 if (Ty->isHalfTy())
476 return 4;
477 if (Ty->isFloatTy())
478 return 5;
479 if (Ty->isDoubleTy())
480 return 6;
481 if (IntegerType *IntTy = dyn_cast<IntegerType>(Ty)) {
482 switch (IntTy->getIntegerBitWidth()) {
483 case 8:
484 return 0;
485 case 16:
486 return 1;
487 case 32:
488 return 2;
489 case 64:
490 return 3;
491 default:
492 llvm_unreachable("invalid integer type");
493 }
494 }
496 Type *EleTy = VecTy->getElementType();
497 unsigned Size = VecTy->getNumElements();
498 return Size << 16 | encodeVecTypeHint(EleTy);
499 }
500 llvm_unreachable("invalid type");
501}
502
503static void addOpsFromMDNode(MDNode *MDN, MCInst &Inst,
505 for (const MDOperand &MDOp : MDN->operands()) {
506 if (auto *CMeta = dyn_cast<ConstantAsMetadata>(MDOp)) {
507 Constant *C = CMeta->getValue();
508 if (ConstantInt *Const = dyn_cast<ConstantInt>(C)) {
509 Inst.addOperand(MCOperand::createImm(Const->getZExtValue()));
510 } else if (auto *CE = dyn_cast<Function>(C)) {
511 MCRegister FuncReg = MAI->getGlobalObjReg(CE);
512 assert(FuncReg.isValid());
513 Inst.addOperand(MCOperand::createReg(FuncReg));
514 }
515 }
516 }
517}
518
519void SPIRVAsmPrinter::outputExecutionModeFromMDNode(
520 MCRegister Reg, MDNode *Node, SPIRV::ExecutionMode::ExecutionMode EM,
521 unsigned ExpectMDOps, int64_t DefVal) {
522 MCInst Inst;
523 Inst.setOpcode(SPIRV::OpExecutionMode);
525 Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(EM)));
526 addOpsFromMDNode(Node, Inst, MAI);
527 // reqd_work_group_size and work_group_size_hint require 3 operands,
528 // if metadata contains less operands, just add a default value
529 unsigned NodeSz = Node->getNumOperands();
530 if (ExpectMDOps > 0 && NodeSz < ExpectMDOps)
531 for (unsigned i = NodeSz; i < ExpectMDOps; ++i)
532 Inst.addOperand(MCOperand::createImm(DefVal));
533 outputMCInst(Inst);
534}
535
536void SPIRVAsmPrinter::outputExecutionModeFromNumthreadsAttribute(
537 const MCRegister &Reg, const Attribute &Attr,
538 SPIRV::ExecutionMode::ExecutionMode EM) {
539 assert(Attr.isValid() && "Function called with an invalid attribute.");
540
541 MCInst Inst;
542 Inst.setOpcode(SPIRV::OpExecutionMode);
544 Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(EM)));
545
546 SmallVector<StringRef> NumThreads;
547 Attr.getValueAsString().split(NumThreads, ',');
548 assert(NumThreads.size() == 3 && "invalid numthreads");
549 for (uint32_t i = 0; i < 3; ++i) {
550 uint32_t V;
551 [[maybe_unused]] bool Result = NumThreads[i].getAsInteger(10, V);
552 assert(!Result && "Failed to parse numthreads");
554 }
555
556 outputMCInst(Inst);
557}
558
559void SPIRVAsmPrinter::emitSimpleExecutionMode(
560 MCRegister Reg, SPIRV::ExecutionMode::ExecutionMode EM) {
561 MCInst Inst;
562 Inst.setOpcode(SPIRV::OpExecutionMode);
564 Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(EM)));
565 outputMCInst(Inst);
566}
567
568void SPIRVAsmPrinter::outputExecutionModeFromEnableMaximalReconvergenceAttr(
569 const MCRegister &Reg, const SPIRVSubtarget &ST) {
570 assert(ST.canUseExtension(SPIRV::Extension::SPV_KHR_maximal_reconvergence) &&
571 "Function called when SPV_KHR_maximal_reconvergence is not enabled.");
572
573 emitSimpleExecutionMode(Reg, SPIRV::ExecutionMode::MaximallyReconvergesKHR);
574}
575
576void SPIRVAsmPrinter::outputExecutionMode(const Module &M) {
577 NamedMDNode *Node = M.getNamedMetadata("spirv.ExecutionMode");
578 if (Node) {
579 for (unsigned i = 0; i < Node->getNumOperands(); i++) {
580 const auto EM =
582 cast<ConstantAsMetadata>((Node->getOperand(i))->getOperand(1))
583 ->getValue())
584 ->getZExtValue();
585 // Skip ArithmeticPoisonKHR to avoid a duplicate.
586 if (EM == SPIRV::ExecutionMode::ArithmeticPoisonKHR)
587 continue;
588 // If SPV_KHR_float_controls2 is enabled and we find any of
589 // FPFastMathDefault, ContractionOff or SignedZeroInfNanPreserve execution
590 // modes, skip it, it'll be done somewhere else.
591 if (ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2)) {
592 if (EM == SPIRV::ExecutionMode::FPFastMathDefault ||
593 EM == SPIRV::ExecutionMode::ContractionOff ||
594 EM == SPIRV::ExecutionMode::SignedZeroInfNanPreserve)
595 continue;
596 }
597
598 MCInst Inst;
599 Inst.setOpcode(SPIRV::OpExecutionMode);
600 addOpsFromMDNode(cast<MDNode>(Node->getOperand(i)), Inst, MAI);
601 outputMCInst(Inst);
602 }
603 outputFPFastMathDefaultInfo();
604 }
605 for (auto FI = M.begin(), E = M.end(); FI != E; ++FI) {
606 const Function &F = *FI;
607 // Only operands of OpEntryPoint instructions are allowed to be
608 // <Entry Point> operands of OpExecutionMode
609 if (F.isDeclaration() || !isEntryPoint(F))
610 continue;
611 MCRegister FReg = MAI->getGlobalObjReg(&F);
612 assert(FReg.isValid());
613
614 if (Attribute Attr = F.getFnAttribute("hlsl.shader"); Attr.isValid()) {
615 // SPIR-V common validation: Fragment requires OriginUpperLeft or
616 // OriginLowerLeft.
617 // VUID-StandaloneSpirv-OriginLowerLeft-04653: Fragment must declare
618 // OriginUpperLeft.
619 if (Attr.getValueAsString() == "pixel") {
620 emitSimpleExecutionMode(FReg, SPIRV::ExecutionMode::OriginUpperLeft);
621 }
622 }
623 if (MDNode *Node = F.getMetadata("reqd_work_group_size"))
624 outputExecutionModeFromMDNode(FReg, Node, SPIRV::ExecutionMode::LocalSize,
625 3, 1);
626 if (Attribute Attr = F.getFnAttribute("hlsl.numthreads"); Attr.isValid())
627 outputExecutionModeFromNumthreadsAttribute(
628 FReg, Attr, SPIRV::ExecutionMode::LocalSize);
629 if (Attribute Attr = F.getFnAttribute("enable-maximal-reconvergence");
630 Attr.getValueAsBool()) {
631 outputExecutionModeFromEnableMaximalReconvergenceAttr(FReg, *ST);
632 }
633 if (MDNode *Node = F.getMetadata("work_group_size_hint"))
634 outputExecutionModeFromMDNode(FReg, Node,
635 SPIRV::ExecutionMode::LocalSizeHint, 3, 1);
636 if (MDNode *Node = F.getMetadata("reqd_sub_group_size"))
637 outputExecutionModeFromMDNode(FReg, Node,
638 SPIRV::ExecutionMode::SubgroupSize, 0, 0);
639 if (MDNode *Node = F.getMetadata("intel_reqd_sub_group_size"))
640 outputExecutionModeFromMDNode(FReg, Node,
641 SPIRV::ExecutionMode::SubgroupSize, 0, 0);
642 if (MDNode *Node = F.getMetadata("max_work_group_size")) {
643 if (ST->canUseExtension(SPIRV::Extension::SPV_INTEL_kernel_attributes))
644 outputExecutionModeFromMDNode(
645 FReg, Node, SPIRV::ExecutionMode::MaxWorkgroupSizeINTEL, 3, 1);
646 }
647 if (MDNode *Node = F.getMetadata("vec_type_hint")) {
648 MCInst Inst;
649 Inst.setOpcode(SPIRV::OpExecutionMode);
651 unsigned EM = static_cast<unsigned>(SPIRV::ExecutionMode::VecTypeHint);
653 unsigned TypeCode = encodeVecTypeHint(getMDOperandAsType(Node, 0));
654 Inst.addOperand(MCOperand::createImm(TypeCode));
655 outputMCInst(Inst);
656 }
657 // Per SPV_KHR_poison_freeze description of PoisonFreezeKHR "If declared,
658 // all entry points must use the ArithmeticPoisonKHR execution mode".
659 if (llvm::is_contained(MAI->Reqs.getMinimalCapabilities(),
660 SPIRV::Capability::PoisonFreezeKHR)) {
661 emitSimpleExecutionMode(FReg, SPIRV::ExecutionMode::ArithmeticPoisonKHR);
662 }
663 // --spirv-fp-contract=off forces to emit ContractionOff for this kernel
664 // entry point, --spirv-fp-contract=fast suppresses it.
665 bool EmitContractionOff =
666 ST->isKernel() && !M.getNamedMetadata("spirv.ExecutionMode") &&
667 SPIRVFPContract != SPIRVFPContractMode::Fast &&
668 (SPIRVFPContract == SPIRVFPContractMode::Off ||
669 !M.getNamedMetadata("opencl.enable.FP_CONTRACT"));
670 if (EmitContractionOff) {
671 if (ST->canUseExtension(SPIRV::Extension::SPV_KHR_float_controls2)) {
672 // When SPV_KHR_float_controls2 is enabled, ContractionOff is
673 // deprecated. We need to use FPFastMathDefault with the appropriate
674 // flags instead. Since FPFastMathDefault takes a target type, we need
675 // to emit it for each floating-point type that exists in the module
676 // to match the effect of ContractionOff. As of now, there are 3 FP
677 // types: fp16, fp32 and fp64.
678
679 // We only end up here because there is no "spirv.ExecutionMode"
680 // metadata, so that means no FPFastMathDefault. Therefore, we only
681 // need to make sure AllowContract is set to 0, as the rest of flags.
682 // We still need to emit the OpExecutionMode instruction, otherwise
683 // it's up to the client API to define the flags. Therefore, we need
684 // to find the constant with 0 value.
685
686 // Collect the SPIRVTypes for fp16, fp32, and fp64 and the constant of
687 // type int32 with 0 value to represent the FP Fast Math Mode.
688 std::vector<const MachineInstr *> SPIRVFloatTypes;
689 const MachineInstr *ConstZeroInt32 = nullptr;
690 for (const MachineInstr *MI :
691 MAI->getMSInstrs(SPIRV::MB_TypeConstVars)) {
692 unsigned OpCode = MI->getOpcode();
693
694 // Collect the SPIRV type if it's a float.
695 if (OpCode == SPIRV::OpTypeFloat) {
696 // Skip if the target type is not fp16, fp32, fp64.
697 const unsigned OpTypeFloatSize = MI->getOperand(1).getImm();
698 if (OpTypeFloatSize != 16 && OpTypeFloatSize != 32 &&
699 OpTypeFloatSize != 64) {
700 continue;
701 }
702 SPIRVFloatTypes.push_back(MI);
703 continue;
704 }
705
706 if (OpCode == SPIRV::OpConstantNull) {
707 // Check if the constant is int32, if not skip it.
708 const MachineRegisterInfo &MRI = MI->getMF()->getRegInfo();
709 MachineInstr *TypeMI = MRI.getVRegDef(MI->getOperand(1).getReg());
710 bool IsInt32Ty = TypeMI &&
711 TypeMI->getOpcode() == SPIRV::OpTypeInt &&
712 TypeMI->getOperand(1).getImm() == 32;
713 if (IsInt32Ty)
714 ConstZeroInt32 = MI;
715 }
716 }
717
718 // When SPV_KHR_float_controls2 is enabled, ContractionOff is
719 // deprecated. We need to use FPFastMathDefault with the appropriate
720 // flags instead. Since FPFastMathDefault takes a target type, we need
721 // to emit it for each floating-point type that exists in the module
722 // to match the effect of ContractionOff. As of now, there are 3 FP
723 // types: fp16, fp32 and fp64.
724 for (const MachineInstr *MI : SPIRVFloatTypes) {
725 MCInst Inst;
726 Inst.setOpcode(SPIRV::OpExecutionModeId);
728 unsigned EM =
729 static_cast<unsigned>(SPIRV::ExecutionMode::FPFastMathDefault);
731 const MachineFunction *MF = MI->getMF();
732 MCRegister TypeReg =
733 MAI->getRegisterAlias(MF, MI->getOperand(0).getReg());
734 Inst.addOperand(MCOperand::createReg(TypeReg));
735 assert(ConstZeroInt32 && "There should be a constant zero.");
736 MCRegister ConstReg = MAI->getRegisterAlias(
737 ConstZeroInt32->getMF(), ConstZeroInt32->getOperand(0).getReg());
738 Inst.addOperand(MCOperand::createReg(ConstReg));
739 outputMCInst(Inst);
740 }
741 } else {
742 emitSimpleExecutionMode(FReg, SPIRV::ExecutionMode::ContractionOff);
743 }
744 }
745 }
746}
747
748void SPIRVAsmPrinter::outputAnnotations(const Module &M) {
749 outputModuleSection(SPIRV::MB_Annotations);
750 // Process llvm.global.annotations special global variable.
751 if (const GlobalVariable *V = M.getNamedGlobal("llvm.global.annotations")) {
752 const ConstantArray *CA = cast<ConstantArray>(V->getOperand(0));
753 for (Value *Op : CA->operands()) {
754 ConstantStruct *CS = cast<ConstantStruct>(Op);
755 // The first field of the struct contains a pointer to
756 // the annotated variable.
757 Value *AnnotatedVar = CS->getOperand(0)->stripPointerCasts();
758 auto *GO = dyn_cast<GlobalObject>(AnnotatedVar);
759 MCRegister Reg = GO ? MAI->getGlobalObjReg(GO) : MCRegister();
760 if (!Reg.isValid()) {
761 std::string DiagMsg;
762 raw_string_ostream OS(DiagMsg);
763 AnnotatedVar->print(OS);
764 DiagMsg = "Unsupported value in llvm.global.annotations: " + DiagMsg;
765 report_fatal_error(DiagMsg.c_str());
766 }
767
768 // The second field contains a pointer to a global annotation string.
769 GlobalVariable *GV =
771
772 StringRef AnnotationString;
773 [[maybe_unused]] bool Success =
774 getConstantStringInfo(GV, AnnotationString);
775 assert(Success && "Failed to get annotation string");
776 MCInst Inst;
777 Inst.setOpcode(SPIRV::OpDecorate);
779 unsigned Dec = static_cast<unsigned>(SPIRV::Decoration::UserSemantic);
781 addStringImm(AnnotationString, Inst);
782 outputMCInst(Inst);
783 }
784 }
785}
786
787void SPIRVAsmPrinter::outputFPFastMathDefaultInfo() {
788 // Collect the SPIRVTypes that are OpTypeFloat and the constants of type
789 // int32, that might be used as FP Fast Math Mode.
790 std::vector<const MachineInstr *> SPIRVFloatTypes;
791 // Hashtable to associate immediate values with the constant holding them.
792 DenseMap<int, const MachineInstr *> ConstMap;
793 for (const MachineInstr *MI : MAI->getMSInstrs(SPIRV::MB_TypeConstVars)) {
794 // Skip if the instruction is not OpTypeFloat or OpConstant.
795 unsigned OpCode = MI->getOpcode();
796 if (OpCode != SPIRV::OpTypeFloat && OpCode != SPIRV::OpConstantI &&
797 OpCode != SPIRV::OpConstantNull)
798 continue;
799
800 // Collect the SPIRV type if it's a float.
801 if (OpCode == SPIRV::OpTypeFloat) {
802 SPIRVFloatTypes.push_back(MI);
803 } else {
804 // Check if the constant is int32, if not skip it.
805 const MachineRegisterInfo &MRI = MI->getMF()->getRegInfo();
806 MachineInstr *TypeMI = MRI.getVRegDef(MI->getOperand(1).getReg());
807 if (!TypeMI || TypeMI->getOpcode() != SPIRV::OpTypeInt ||
808 TypeMI->getOperand(1).getImm() != 32)
809 continue;
810
811 if (OpCode == SPIRV::OpConstantI)
812 ConstMap[MI->getOperand(2).getImm()] = MI;
813 else
814 ConstMap[0] = MI;
815 }
816 }
817
818 for (const auto &[Func, FPFastMathDefaultInfoVec] :
819 MAI->FPFastMathDefaultInfoMap) {
820 if (FPFastMathDefaultInfoVec.empty())
821 continue;
822
823 for (const MachineInstr *MI : SPIRVFloatTypes) {
824 unsigned OpTypeFloatSize = MI->getOperand(1).getImm();
827 assert(Index < FPFastMathDefaultInfoVec.size() &&
828 "Index out of bounds for FPFastMathDefaultInfoVec");
829 const auto &FPFastMathDefaultInfo = FPFastMathDefaultInfoVec[Index];
830 assert(FPFastMathDefaultInfo.Ty &&
831 "Expected target type for FPFastMathDefaultInfo");
832 assert(FPFastMathDefaultInfo.Ty->getScalarSizeInBits() ==
833 OpTypeFloatSize &&
834 "Mismatched float type size");
835 MCInst Inst;
836 Inst.setOpcode(SPIRV::OpExecutionModeId);
837 MCRegister FuncReg = MAI->getGlobalObjReg(Func);
838 assert(FuncReg.isValid());
839 Inst.addOperand(MCOperand::createReg(FuncReg));
840 Inst.addOperand(
841 MCOperand::createImm(SPIRV::ExecutionMode::FPFastMathDefault));
842 MCRegister TypeReg =
843 MAI->getRegisterAlias(MI->getMF(), MI->getOperand(0).getReg());
844 Inst.addOperand(MCOperand::createReg(TypeReg));
845 unsigned Flags = FPFastMathDefaultInfo.FastMathFlags;
846 if (FPFastMathDefaultInfo.ContractionOff &&
847 (Flags & SPIRV::FPFastMathMode::AllowContract))
849 "Conflicting FPFastMathFlags: ContractionOff and AllowContract");
850
851 if (FPFastMathDefaultInfo.SignedZeroInfNanPreserve &&
852 !(Flags &
853 (SPIRV::FPFastMathMode::NotNaN | SPIRV::FPFastMathMode::NotInf |
854 SPIRV::FPFastMathMode::NSZ))) {
855 if (FPFastMathDefaultInfo.FPFastMathDefault)
856 report_fatal_error("Conflicting FPFastMathFlags: "
857 "SignedZeroInfNanPreserve but at least one of "
858 "NotNaN/NotInf/NSZ is enabled.");
859 }
860
861 // Don't emit if none of the execution modes was used.
862 if (Flags == SPIRV::FPFastMathMode::None &&
863 !FPFastMathDefaultInfo.ContractionOff &&
864 !FPFastMathDefaultInfo.SignedZeroInfNanPreserve &&
865 !FPFastMathDefaultInfo.FPFastMathDefault)
866 continue;
867
868 // Retrieve the constant instruction for the immediate value.
869 auto It = ConstMap.find(Flags);
870 if (It == ConstMap.end())
871 report_fatal_error("Expected constant instruction for FP Fast Math "
872 "Mode operand of FPFastMathDefault execution mode.");
873 const MachineInstr *ConstMI = It->second;
874 MCRegister ConstReg = MAI->getRegisterAlias(
875 ConstMI->getMF(), ConstMI->getOperand(0).getReg());
876 Inst.addOperand(MCOperand::createReg(ConstReg));
877 outputMCInst(Inst);
878 }
879 }
880}
881
882void SPIRVAsmPrinter::outputModuleSections() {
883 const Module *M = MMI->getModule();
884 // Get the global subtarget to output module-level info.
885 ST = static_cast<const SPIRVTargetMachine &>(TM).getSubtargetImpl();
886 TII = ST->getInstrInfo();
887 MAI = &getAnalysis<SPIRVModuleAnalysis>().MAI;
888 assert(ST && TII && MAI && M && "Module analysis is required");
889
890 if (!AuxDataHandler) {
891 auto Handler = std::make_unique<SPIRVAuxDataHandler>(*this, *M);
892 if (Handler->hasWork())
893 AuxDataHandler = std::move(Handler);
894 }
895
896 // Let the NSDI handler add its extension and ext inst import entry to MAI
897 // before the module header sections are emitted.
898 if (NSDebugHandler)
899 NSDebugHandler->prepareModuleOutput(*ST, *MAI);
900 if (AuxDataHandler)
901 AuxDataHandler->prepareModuleOutput(*ST, *MAI);
902
903 // Output instructions according to the Logical Layout of a Module:
904 // 1,2. All OpCapability instructions, then optional OpExtension
905 // instructions.
906 outputGlobalRequirements();
907 // 3. Optional OpExtInstImport instructions.
908 outputOpExtInstImports(*M);
909 // 4. The single required OpMemoryModel instruction.
910 outputOpMemoryModel();
911 // 5. All entry point declarations, using OpEntryPoint.
912 outputEntryPoints();
913 // 6. Execution-mode declarations, using OpExecutionMode or
914 // OpExecutionModeId.
915 outputExecutionMode(*M);
916 // 7a. Debug: all OpString, OpSourceExtension, OpSource, and
917 // OpSourceContinued, without forward references.
918 outputDebugSourceAndStrings(*M);
919 // 7b. Debug: all OpName and all OpMemberName.
920 outputModuleSection(SPIRV::MB_DebugNames);
921 // 7c. Debug: all OpModuleProcessed instructions.
922 outputModuleSection(SPIRV::MB_DebugModuleProcessed);
923 // xxx. SPV_INTEL_memory_access_aliasing instructions go before 8.
924 // "All annotation instructions"
925 outputModuleSection(SPIRV::MB_AliasingInsts);
926 // 8. All annotation instructions (all decorations).
927 outputAnnotations(*M);
928 // 9. All type declarations (OpTypeXXX instructions), all constant
929 // instructions, and all global variable declarations. This section is
930 // the first section to allow use of: OpLine and OpNoLine debug information;
931 // non-semantic instructions with OpExtInst.
932 outputModuleSection(SPIRV::MB_TypeConstVars);
933 // 10. All global NonSemantic.Shader.DebugInfo.100 instructions. The
934 // SPIRVNonSemanticDebugHandler emits these directly as MCInsts; the
935 // MB_NonSemanticGlobalDI section in MAI is intentionally left empty.
936 if (NSDebugHandler)
937 NSDebugHandler->emitNonSemanticGlobalDebugInfo(*MAI);
938 if (AuxDataHandler)
939 AuxDataHandler->emitAuxData(*MAI);
940 // 11. All function declarations (functions without a body).
941 outputExtFuncDecls();
942 // 12. All function definitions (functions with a body).
943 // This is done in regular function output.
944}
945
946bool SPIRVAsmPrinter::doInitialization(Module &M) {
947 ModuleSectionsEmitted = false;
948 if (!M.getModuleInlineAsm().empty()) {
949 M.getContext().emitError(
950 "SPIR-V does not support module-level inline assembly");
951 M.removeModuleInlineAsm();
952 }
953
954 // Register the NSDI handler before calling the base class so that
955 // AsmPrinter::doInitialization() calls Handler->beginModule(M) for it.
956 if (M.getNamedMetadata("llvm.dbg.cu")) {
957 auto Handler = std::make_unique<SPIRVNonSemanticDebugHandler>(*this);
958 NSDebugHandler = Handler.get();
959 addAsmPrinterHandler(std::move(Handler));
960 }
961 // We need to call the parent's one explicitly.
963}
964
965char SPIRVAsmPrinter::ID = 0;
966
967INITIALIZE_PASS(SPIRVAsmPrinter, "spirv-asm-printer", "SPIRV Assembly Printer",
968 false, false)
969
970// Force static initialization.
972LLVMInitializeSPIRVAsmPrinter() {
976}
#define Success
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
#define X(NUM, ENUM, NAME)
Definition ELF.h:856
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
#define LLVM_ABI
Definition Compiler.h:215
#define LLVM_EXTERNAL_VISIBILITY
Definition Compiler.h:132
This file defines the DenseMap class.
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Machine Check Debug Module
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
Register Reg
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static void addOpsFromMDNode(MDNode *MDN, MCInst &Inst, SPIRV::ModuleAnalysisInfo *MAI)
static bool isFuncOrHeaderInstr(const MachineInstr *MI, const SPIRVInstrInfo *TII)
static unsigned encodeVecTypeHint(Type *Ty)
#define SPIRV_BACKEND_SERVICE_FUN_NAME
Definition SPIRVUtils.h:543
static bool printOperand(raw_ostream &OS, const SelectionDAG *G, const SDValue Value)
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
This class is intended to be used as a driving class for all asm writers.
Definition AsmPrinter.h:91
bool doInitialization(Module &M) override
Set up the AsmPrinter when we are working on a new module.
void getAnalysisUsage(AnalysisUsage &AU) const override
Record analysis usage.
Functions, function parameters, and return types can have attributes to indicate how they should be t...
Definition Attributes.h:105
LLVM_ABI bool getValueAsBool() const
Return the attribute's value as a boolean.
LLVM_ABI StringRef getValueAsString() const
Return the attribute's value as a string.
bool isValid() const
Return true if the attribute is any kind of attribute.
Definition Attributes.h:261
This is the shared class of boolean and integer constants.
Definition Constants.h:87
This is an important base class in LLVM.
Definition Constant.h:43
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:223
iterator end()
Definition DenseMap.h:141
Class to represent fixed width SIMD vectors.
static StringRef dropLLVMManglingEscape(StringRef Name)
If the given string begins with the GlobalValue name mangling escape character '\1',...
Class to represent integer types.
Instances of this class represent a single low-level machine instruction.
Definition MCInst.h:188
void addOperand(const MCOperand Op)
Definition MCInst.h:215
void setOpcode(unsigned Op)
Definition MCInst.h:201
static MCOperand createReg(MCRegister Reg)
Definition MCInst.h:138
static MCOperand createImm(int64_t Val)
Definition MCInst.h:145
Wrapper class representing physical registers. Should be passed by value.
Definition MCRegister.h:41
constexpr bool isValid() const
Definition MCRegister.h:84
StringRef getName() const
getName - Get the symbol name.
Definition MCSymbol.h:188
Metadata node.
Definition Metadata.h:1069
ArrayRef< MDOperand > operands() const
Definition Metadata.h:1424
Tracking metadata reference owned by Metadata.
Definition Metadata.h:891
LLVM_ABI MCSymbol * getSymbol() const
Return the MCSymbol for this basic block.
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
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
const GlobalValue * getGlobal() const
int64_t getImm() const
MachineBasicBlock * getMBB() const
const BlockAddress * getBlockAddress() const
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
const char * getSymbolName() const
Register getReg() const
getReg - Returns the register number.
const ConstantFP * getFPImm() const
@ MO_Immediate
Immediate operand.
@ MO_ConstantPoolIndex
Address of indexed Constant in Constant Pool.
@ MO_GlobalAddress
Address of a global value.
@ MO_BlockAddress
Address of a basic block.
@ MO_MachineBasicBlock
MachineBasicBlock reference.
@ MO_Register
Register operand.
@ MO_ExternalSymbol
Name of external global symbol.
@ MO_JumpTableIndex
Address of indexed Jump Table for switch.
@ MO_FPImmediate
Floating-point immediate operand.
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
constexpr bool isValid() const
Definition Register.h:112
static const char * getRegisterName(MCRegister Reg)
void lower(const MachineInstr *MI, MCInst &OutMI, SPIRV::ModuleAnalysisInfo *MAI) const
AsmPrinter handler that emits NonSemantic.Shader.DebugInfo.100 (NSDI) instructions for the SPIR-V bac...
void emitNonSemanticDebugStrings(SPIRV::ModuleAnalysisInfo &MAI)
Emit OpString instructions for all NSDI file paths and basic type names into the debug section (secti...
void emitNonSemanticGlobalDebugInfo(SPIRV::ModuleAnalysisInfo &MAI)
Emit module-scope NSDI instructions (DebugSource, DebugCompilationUnit, DebugTypeBasic,...
void prepareModuleOutput(const SPIRVSubtarget &ST, SPIRV::ModuleAnalysisInfo &MAI)
Add SPV_KHR_non_semantic_info extension and NonSemantic.Shader.DebugInfo.100 ext inst set entry to MA...
void notifyEntryLabelEmitted(const MachineFunction &MF)
Called after the synthesized entry OpLabel has been emitted.
const SPIRVInstrInfo * getInstrInfo() const override
bool isAtLeastSPIRVVer(VersionTuple VerToCompareTo) const
SPIRVGlobalRegistry * getSPIRVGlobalRegistry() const
VersionTuple getSPIRVVersion() const
unsigned getBound() const
bool canUseExtension(SPIRV::Extension::Extension E) const
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition StringRef.h:736
Primary interface to the complete machine description for the target machine.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
op_range operands()
Definition User.h:267
Value * getOperand(unsigned i) const
Definition User.h:207
LLVM_ABI void print(raw_ostream &O, bool IsForDebug=false) const
Implement operator<< on Value.
LLVM_ABI const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
Definition Value.cpp:713
unsigned getMajor() const
Retrieve the major version number.
std::optional< unsigned > getMinor() const
Retrieve the minor version number, if provided.
std::pair< iterator, bool > insert(const ValueT &V)
Definition DenseSet.h:209
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
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)
NodeAddr< NodeBase * > Node
Definition RDFGraph.h:381
unsigned getOpcode(const VPValue *V)
Return the instruction opcode for the recipe defining V or 0 for unsupported recipes and VPValues not...
This is an optimization pass for GlobalISel generic memory operations.
void addStringImm(StringRef Str, MCInst &Inst)
Target & getTheSPIRV32Target()
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
DenseMap< Value *, Constant * > ConstMap
LLVM_ABI bool getConstantStringInfo(const Value *V, StringRef &Str, bool TrimAtNul=true)
This function computes the length of a null-terminated C string pointed to by V.
std::string getExtInstSetName(SPIRV::InstructionSet::InstructionSet Set)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
std::string getSymbolicOperandMnemonic(SPIRV::OperandCategory::OperandCategory Category, int32_t Value)
bool isEntryPoint(const Function &F)
Target & getTheSPIRV64Target()
Target & getTheSPIRVLogicalTarget()
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
Type * getMDOperandAsType(const MDNode *N, unsigned I)
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1947
RegisterAsmPrinter - Helper template for registering a target specific assembly printer,...
static size_t computeFPFastMathDefaultInfoVecIndex(size_t BitWidth)
Definition SPIRVUtils.h:154
MCRegister getGlobalObjReg(const GlobalObject *GO)