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