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