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