1 //===-- SPIRVAsmPrinter.cpp - SPIR-V LLVM assembly writer ------*- C++ -*--===//
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
7 //===----------------------------------------------------------------------===//
9 // This file contains a printer that converts from our internal representation
10 // of machine-dependent LLVM code to the SPIR-V assembly language.
12 //===----------------------------------------------------------------------===//
14 #include "MCTargetDesc/SPIRVInstPrinter.h"
16 #include "SPIRVInstrInfo.h"
17 #include "SPIRVMCInstLower.h"
18 #include "SPIRVModuleAnalysis.h"
19 #include "SPIRVSubtarget.h"
20 #include "SPIRVTargetMachine.h"
21 #include "SPIRVUtils.h"
22 #include "TargetInfo/SPIRVTargetInfo.h"
23 #include "llvm/ADT/DenseMap.h"
24 #include "llvm/Analysis/ValueTracking.h"
25 #include "llvm/CodeGen/AsmPrinter.h"
26 #include "llvm/CodeGen/MachineConstantPool.h"
27 #include "llvm/CodeGen/MachineFunctionPass.h"
28 #include "llvm/CodeGen/MachineInstr.h"
29 #include "llvm/CodeGen/MachineModuleInfo.h"
30 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
31 #include "llvm/MC/MCAsmInfo.h"
32 #include "llvm/MC/MCInst.h"
33 #include "llvm/MC/MCStreamer.h"
34 #include "llvm/MC/MCSymbol.h"
35 #include "llvm/MC/TargetRegistry.h"
36 #include "llvm/Support/raw_ostream.h"
40 #define DEBUG_TYPE "asm-printer"
43 class SPIRVAsmPrinter
: public AsmPrinter
{
45 explicit SPIRVAsmPrinter(TargetMachine
&TM
,
46 std::unique_ptr
<MCStreamer
> Streamer
)
47 : AsmPrinter(TM
, std::move(Streamer
)), ST(nullptr), TII(nullptr) {}
48 bool ModuleSectionsEmitted
;
49 const SPIRVSubtarget
*ST
;
50 const SPIRVInstrInfo
*TII
;
52 StringRef
getPassName() const override
{ return "SPIRV Assembly Printer"; }
53 void printOperand(const MachineInstr
*MI
, int OpNum
, raw_ostream
&O
);
54 bool PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
55 const char *ExtraCode
, raw_ostream
&O
) override
;
57 void outputMCInst(MCInst
&Inst
);
58 void outputInstruction(const MachineInstr
*MI
);
59 void outputModuleSection(SPIRV::ModuleSectionType MSType
);
60 void outputGlobalRequirements();
61 void outputEntryPoints();
62 void outputDebugSourceAndStrings(const Module
&M
);
63 void outputOpExtInstImports(const Module
&M
);
64 void outputOpMemoryModel();
65 void outputOpFunctionEnd();
66 void outputExtFuncDecls();
67 void outputExecutionModeFromMDNode(Register Reg
, MDNode
*Node
,
68 SPIRV::ExecutionMode::ExecutionMode EM
);
69 void outputExecutionModeFromNumthreadsAttribute(
70 const Register
&Reg
, const Attribute
&Attr
,
71 SPIRV::ExecutionMode::ExecutionMode EM
);
72 void outputExecutionMode(const Module
&M
);
73 void outputAnnotations(const Module
&M
);
74 void outputModuleSections();
76 void emitInstruction(const MachineInstr
*MI
) override
;
77 void emitFunctionEntryLabel() override
{}
78 void emitFunctionHeader() override
;
79 void emitFunctionBodyStart() override
{}
80 void emitFunctionBodyEnd() override
;
81 void emitBasicBlockStart(const MachineBasicBlock
&MBB
) override
;
82 void emitBasicBlockEnd(const MachineBasicBlock
&MBB
) override
{}
83 void emitGlobalVariable(const GlobalVariable
*GV
) override
{}
84 void emitOpLabel(const MachineBasicBlock
&MBB
);
85 void emitEndOfAsmFile(Module
&M
) override
;
86 bool doInitialization(Module
&M
) override
;
88 void getAnalysisUsage(AnalysisUsage
&AU
) const override
;
89 SPIRV::ModuleAnalysisInfo
*MAI
;
93 void SPIRVAsmPrinter::getAnalysisUsage(AnalysisUsage
&AU
) const {
94 AU
.addRequired
<SPIRVModuleAnalysis
>();
95 AU
.addPreserved
<SPIRVModuleAnalysis
>();
96 AsmPrinter::getAnalysisUsage(AU
);
99 // If the module has no functions, we need output global info anyway.
100 void SPIRVAsmPrinter::emitEndOfAsmFile(Module
&M
) {
101 if (ModuleSectionsEmitted
== false) {
102 outputModuleSections();
103 ModuleSectionsEmitted
= true;
107 void SPIRVAsmPrinter::emitFunctionHeader() {
108 if (ModuleSectionsEmitted
== false) {
109 outputModuleSections();
110 ModuleSectionsEmitted
= true;
112 // Get the subtarget from the current MachineFunction.
113 ST
= &MF
->getSubtarget
<SPIRVSubtarget
>();
114 TII
= ST
->getInstrInfo();
115 const Function
&F
= MF
->getFunction();
118 OutStreamer
->getCommentOS()
119 << "-- Begin function "
120 << GlobalValue::dropLLVMManglingEscape(F
.getName()) << '\n';
123 auto Section
= getObjFileLowering().SectionForGlobal(&F
, TM
);
124 MF
->setSection(Section
);
127 void SPIRVAsmPrinter::outputOpFunctionEnd() {
128 MCInst FunctionEndInst
;
129 FunctionEndInst
.setOpcode(SPIRV::OpFunctionEnd
);
130 outputMCInst(FunctionEndInst
);
133 // Emit OpFunctionEnd at the end of MF and clear BBNumToRegMap.
134 void SPIRVAsmPrinter::emitFunctionBodyEnd() {
135 outputOpFunctionEnd();
136 MAI
->BBNumToRegMap
.clear();
139 void SPIRVAsmPrinter::emitOpLabel(const MachineBasicBlock
&MBB
) {
141 LabelInst
.setOpcode(SPIRV::OpLabel
);
142 LabelInst
.addOperand(MCOperand::createReg(MAI
->getOrCreateMBBRegister(MBB
)));
143 outputMCInst(LabelInst
);
146 void SPIRVAsmPrinter::emitBasicBlockStart(const MachineBasicBlock
&MBB
) {
147 assert(!MBB
.empty() && "MBB is empty!");
149 // If it's the first MBB in MF, it has OpFunction and OpFunctionParameter, so
150 // OpLabel should be output after them.
151 if (MBB
.getNumber() == MF
->front().getNumber()) {
152 for (const MachineInstr
&MI
: MBB
)
153 if (MI
.getOpcode() == SPIRV::OpFunction
)
155 // TODO: this case should be checked by the verifier.
156 report_fatal_error("OpFunction is expected in the front MBB of MF");
161 void SPIRVAsmPrinter::printOperand(const MachineInstr
*MI
, int OpNum
,
163 const MachineOperand
&MO
= MI
->getOperand(OpNum
);
165 switch (MO
.getType()) {
166 case MachineOperand::MO_Register
:
167 O
<< SPIRVInstPrinter::getRegisterName(MO
.getReg());
170 case MachineOperand::MO_Immediate
:
174 case MachineOperand::MO_FPImmediate
:
178 case MachineOperand::MO_MachineBasicBlock
:
179 O
<< *MO
.getMBB()->getSymbol();
182 case MachineOperand::MO_GlobalAddress
:
183 O
<< *getSymbol(MO
.getGlobal());
186 case MachineOperand::MO_BlockAddress
: {
187 MCSymbol
*BA
= GetBlockAddressSymbol(MO
.getBlockAddress());
192 case MachineOperand::MO_ExternalSymbol
:
193 O
<< *GetExternalSymbolSymbol(MO
.getSymbolName());
196 case MachineOperand::MO_JumpTableIndex
:
197 case MachineOperand::MO_ConstantPoolIndex
:
199 llvm_unreachable("<unknown operand type>");
203 bool SPIRVAsmPrinter::PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
204 const char *ExtraCode
, raw_ostream
&O
) {
205 if (ExtraCode
&& ExtraCode
[0])
206 return true; // Invalid instruction - SPIR-V does not have special modifiers
208 printOperand(MI
, OpNo
, O
);
212 static bool isFuncOrHeaderInstr(const MachineInstr
*MI
,
213 const SPIRVInstrInfo
*TII
) {
214 return TII
->isHeaderInstr(*MI
) || MI
->getOpcode() == SPIRV::OpFunction
||
215 MI
->getOpcode() == SPIRV::OpFunctionParameter
;
218 void SPIRVAsmPrinter::outputMCInst(MCInst
&Inst
) {
219 OutStreamer
->emitInstruction(Inst
, *OutContext
.getSubtargetInfo());
222 void SPIRVAsmPrinter::outputInstruction(const MachineInstr
*MI
) {
223 SPIRVMCInstLower MCInstLowering
;
225 MCInstLowering
.lower(MI
, TmpInst
, MAI
);
226 outputMCInst(TmpInst
);
229 void SPIRVAsmPrinter::emitInstruction(const MachineInstr
*MI
) {
230 SPIRV_MC::verifyInstructionPredicates(MI
->getOpcode(),
231 getSubtargetInfo().getFeatureBits());
233 if (!MAI
->getSkipEmission(MI
))
234 outputInstruction(MI
);
236 // Output OpLabel after OpFunction and OpFunctionParameter in the first MBB.
237 const MachineInstr
*NextMI
= MI
->getNextNode();
238 if (!MAI
->hasMBBRegister(*MI
->getParent()) && isFuncOrHeaderInstr(MI
, TII
) &&
239 (!NextMI
|| !isFuncOrHeaderInstr(NextMI
, TII
))) {
240 assert(MI
->getParent()->getNumber() == MF
->front().getNumber() &&
241 "OpFunction is not in the front MBB of MF");
242 emitOpLabel(*MI
->getParent());
246 void SPIRVAsmPrinter::outputModuleSection(SPIRV::ModuleSectionType MSType
) {
247 for (MachineInstr
*MI
: MAI
->getMSInstrs(MSType
))
248 outputInstruction(MI
);
251 void SPIRVAsmPrinter::outputDebugSourceAndStrings(const Module
&M
) {
252 // Output OpSourceExtensions.
253 for (auto &Str
: MAI
->SrcExt
) {
255 Inst
.setOpcode(SPIRV::OpSourceExtension
);
256 addStringImm(Str
.first(), Inst
);
261 Inst
.setOpcode(SPIRV::OpSource
);
262 Inst
.addOperand(MCOperand::createImm(static_cast<unsigned>(MAI
->SrcLang
)));
264 MCOperand::createImm(static_cast<unsigned>(MAI
->SrcLangVersion
)));
268 void SPIRVAsmPrinter::outputOpExtInstImports(const Module
&M
) {
269 for (auto &CU
: MAI
->ExtInstSetMap
) {
270 unsigned Set
= CU
.first
;
271 Register Reg
= CU
.second
;
273 Inst
.setOpcode(SPIRV::OpExtInstImport
);
274 Inst
.addOperand(MCOperand::createReg(Reg
));
275 addStringImm(getExtInstSetName(
276 static_cast<SPIRV::InstructionSet::InstructionSet
>(Set
)),
282 void SPIRVAsmPrinter::outputOpMemoryModel() {
284 Inst
.setOpcode(SPIRV::OpMemoryModel
);
285 Inst
.addOperand(MCOperand::createImm(static_cast<unsigned>(MAI
->Addr
)));
286 Inst
.addOperand(MCOperand::createImm(static_cast<unsigned>(MAI
->Mem
)));
290 // Before the OpEntryPoints' output, we need to add the entry point's
291 // interfaces. The interface is a list of IDs of global OpVariable instructions.
292 // These declare the set of global variables from a module that form
293 // the interface of this entry point.
294 void SPIRVAsmPrinter::outputEntryPoints() {
295 // Find all OpVariable IDs with required StorageClass.
296 DenseSet
<Register
> InterfaceIDs
;
297 for (MachineInstr
*MI
: MAI
->GlobalVarList
) {
298 assert(MI
->getOpcode() == SPIRV::OpVariable
);
299 auto SC
= static_cast<SPIRV::StorageClass::StorageClass
>(
300 MI
->getOperand(2).getImm());
301 // Before version 1.4, the interface's storage classes are limited to
302 // the Input and Output storage classes. Starting with version 1.4,
303 // the interface's storage classes are all storage classes used in
304 // declaring all global variables referenced by the entry point call tree.
305 if (ST
->getSPIRVVersion() >= 14 || SC
== SPIRV::StorageClass::Input
||
306 SC
== SPIRV::StorageClass::Output
) {
307 MachineFunction
*MF
= MI
->getMF();
308 Register Reg
= MAI
->getRegisterAlias(MF
, MI
->getOperand(0).getReg());
309 InterfaceIDs
.insert(Reg
);
313 // Output OpEntryPoints adding interface args to all of them.
314 for (MachineInstr
*MI
: MAI
->getMSInstrs(SPIRV::MB_EntryPoints
)) {
315 SPIRVMCInstLower MCInstLowering
;
317 MCInstLowering
.lower(MI
, TmpInst
, MAI
);
318 for (Register Reg
: InterfaceIDs
) {
319 assert(Reg
.isValid());
320 TmpInst
.addOperand(MCOperand::createReg(Reg
));
322 outputMCInst(TmpInst
);
326 // Create global OpCapability instructions for the required capabilities.
327 void SPIRVAsmPrinter::outputGlobalRequirements() {
328 // Abort here if not all requirements can be satisfied.
329 MAI
->Reqs
.checkSatisfiable(*ST
);
331 for (const auto &Cap
: MAI
->Reqs
.getMinimalCapabilities()) {
333 Inst
.setOpcode(SPIRV::OpCapability
);
334 Inst
.addOperand(MCOperand::createImm(Cap
));
338 // Generate the final OpExtensions with strings instead of enums.
339 for (const auto &Ext
: MAI
->Reqs
.getExtensions()) {
341 Inst
.setOpcode(SPIRV::OpExtension
);
342 addStringImm(getSymbolicOperandMnemonic(
343 SPIRV::OperandCategory::ExtensionOperand
, Ext
),
347 // TODO add a pseudo instr for version number.
350 void SPIRVAsmPrinter::outputExtFuncDecls() {
351 // Insert OpFunctionEnd after each declaration.
352 SmallVectorImpl
<MachineInstr
*>::iterator
353 I
= MAI
->getMSInstrs(SPIRV::MB_ExtFuncDecls
).begin(),
354 E
= MAI
->getMSInstrs(SPIRV::MB_ExtFuncDecls
).end();
355 for (; I
!= E
; ++I
) {
356 outputInstruction(*I
);
357 if ((I
+ 1) == E
|| (*(I
+ 1))->getOpcode() == SPIRV::OpFunction
)
358 outputOpFunctionEnd();
362 // Encode LLVM type by SPIR-V execution mode VecTypeHint.
363 static unsigned encodeVecTypeHint(Type
*Ty
) {
368 if (Ty
->isDoubleTy())
370 if (IntegerType
*IntTy
= dyn_cast
<IntegerType
>(Ty
)) {
371 switch (IntTy
->getIntegerBitWidth()) {
381 llvm_unreachable("invalid integer type");
384 if (FixedVectorType
*VecTy
= dyn_cast
<FixedVectorType
>(Ty
)) {
385 Type
*EleTy
= VecTy
->getElementType();
386 unsigned Size
= VecTy
->getNumElements();
387 return Size
<< 16 | encodeVecTypeHint(EleTy
);
389 llvm_unreachable("invalid type");
392 static void addOpsFromMDNode(MDNode
*MDN
, MCInst
&Inst
,
393 SPIRV::ModuleAnalysisInfo
*MAI
) {
394 for (const MDOperand
&MDOp
: MDN
->operands()) {
395 if (auto *CMeta
= dyn_cast
<ConstantAsMetadata
>(MDOp
)) {
396 Constant
*C
= CMeta
->getValue();
397 if (ConstantInt
*Const
= dyn_cast
<ConstantInt
>(C
)) {
398 Inst
.addOperand(MCOperand::createImm(Const
->getZExtValue()));
399 } else if (auto *CE
= dyn_cast
<Function
>(C
)) {
400 Register FuncReg
= MAI
->getFuncReg(CE
);
401 assert(FuncReg
.isValid());
402 Inst
.addOperand(MCOperand::createReg(FuncReg
));
408 void SPIRVAsmPrinter::outputExecutionModeFromMDNode(
409 Register Reg
, MDNode
*Node
, SPIRV::ExecutionMode::ExecutionMode EM
) {
411 Inst
.setOpcode(SPIRV::OpExecutionMode
);
412 Inst
.addOperand(MCOperand::createReg(Reg
));
413 Inst
.addOperand(MCOperand::createImm(static_cast<unsigned>(EM
)));
414 addOpsFromMDNode(Node
, Inst
, MAI
);
418 void SPIRVAsmPrinter::outputExecutionModeFromNumthreadsAttribute(
419 const Register
&Reg
, const Attribute
&Attr
,
420 SPIRV::ExecutionMode::ExecutionMode EM
) {
421 assert(Attr
.isValid() && "Function called with an invalid attribute.");
424 Inst
.setOpcode(SPIRV::OpExecutionMode
);
425 Inst
.addOperand(MCOperand::createReg(Reg
));
426 Inst
.addOperand(MCOperand::createImm(static_cast<unsigned>(EM
)));
428 SmallVector
<StringRef
> NumThreads
;
429 Attr
.getValueAsString().split(NumThreads
, ',');
430 assert(NumThreads
.size() == 3 && "invalid numthreads");
431 for (uint32_t i
= 0; i
< 3; ++i
) {
433 [[maybe_unused
]] bool Result
= NumThreads
[i
].getAsInteger(10, V
);
434 assert(!Result
&& "Failed to parse numthreads");
435 Inst
.addOperand(MCOperand::createImm(V
));
441 void SPIRVAsmPrinter::outputExecutionMode(const Module
&M
) {
442 NamedMDNode
*Node
= M
.getNamedMetadata("spirv.ExecutionMode");
444 for (unsigned i
= 0; i
< Node
->getNumOperands(); i
++) {
446 Inst
.setOpcode(SPIRV::OpExecutionMode
);
447 addOpsFromMDNode(cast
<MDNode
>(Node
->getOperand(i
)), Inst
, MAI
);
451 for (auto FI
= M
.begin(), E
= M
.end(); FI
!= E
; ++FI
) {
452 const Function
&F
= *FI
;
453 if (F
.isDeclaration())
455 Register FReg
= MAI
->getFuncReg(&F
);
456 assert(FReg
.isValid());
457 if (MDNode
*Node
= F
.getMetadata("reqd_work_group_size"))
458 outputExecutionModeFromMDNode(FReg
, Node
,
459 SPIRV::ExecutionMode::LocalSize
);
460 if (Attribute Attr
= F
.getFnAttribute("hlsl.numthreads"); Attr
.isValid())
461 outputExecutionModeFromNumthreadsAttribute(
462 FReg
, Attr
, SPIRV::ExecutionMode::LocalSize
);
463 if (MDNode
*Node
= F
.getMetadata("work_group_size_hint"))
464 outputExecutionModeFromMDNode(FReg
, Node
,
465 SPIRV::ExecutionMode::LocalSizeHint
);
466 if (MDNode
*Node
= F
.getMetadata("intel_reqd_sub_group_size"))
467 outputExecutionModeFromMDNode(FReg
, Node
,
468 SPIRV::ExecutionMode::SubgroupSize
);
469 if (MDNode
*Node
= F
.getMetadata("vec_type_hint")) {
471 Inst
.setOpcode(SPIRV::OpExecutionMode
);
472 Inst
.addOperand(MCOperand::createReg(FReg
));
473 unsigned EM
= static_cast<unsigned>(SPIRV::ExecutionMode::VecTypeHint
);
474 Inst
.addOperand(MCOperand::createImm(EM
));
475 unsigned TypeCode
= encodeVecTypeHint(getMDOperandAsType(Node
, 0));
476 Inst
.addOperand(MCOperand::createImm(TypeCode
));
479 if (ST
->isOpenCLEnv() && !M
.getNamedMetadata("spirv.ExecutionMode") &&
480 !M
.getNamedMetadata("opencl.enable.FP_CONTRACT")) {
482 Inst
.setOpcode(SPIRV::OpExecutionMode
);
483 Inst
.addOperand(MCOperand::createReg(FReg
));
484 unsigned EM
= static_cast<unsigned>(SPIRV::ExecutionMode::ContractionOff
);
485 Inst
.addOperand(MCOperand::createImm(EM
));
491 void SPIRVAsmPrinter::outputAnnotations(const Module
&M
) {
492 outputModuleSection(SPIRV::MB_Annotations
);
493 // Process llvm.global.annotations special global variable.
494 for (auto F
= M
.global_begin(), E
= M
.global_end(); F
!= E
; ++F
) {
495 if ((*F
).getName() != "llvm.global.annotations")
497 const GlobalVariable
*V
= &(*F
);
498 const ConstantArray
*CA
= cast
<ConstantArray
>(V
->getOperand(0));
499 for (Value
*Op
: CA
->operands()) {
500 ConstantStruct
*CS
= cast
<ConstantStruct
>(Op
);
501 // The first field of the struct contains a pointer to
502 // the annotated variable.
503 Value
*AnnotatedVar
= CS
->getOperand(0)->stripPointerCasts();
504 if (!isa
<Function
>(AnnotatedVar
))
505 report_fatal_error("Unsupported value in llvm.global.annotations");
506 Function
*Func
= cast
<Function
>(AnnotatedVar
);
507 Register Reg
= MAI
->getFuncReg(Func
);
509 // The second field contains a pointer to a global annotation string.
511 cast
<GlobalVariable
>(CS
->getOperand(1)->stripPointerCasts());
513 StringRef AnnotationString
;
514 getConstantStringInfo(GV
, AnnotationString
);
516 Inst
.setOpcode(SPIRV::OpDecorate
);
517 Inst
.addOperand(MCOperand::createReg(Reg
));
518 unsigned Dec
= static_cast<unsigned>(SPIRV::Decoration::UserSemantic
);
519 Inst
.addOperand(MCOperand::createImm(Dec
));
520 addStringImm(AnnotationString
, Inst
);
526 void SPIRVAsmPrinter::outputModuleSections() {
527 const Module
*M
= MMI
->getModule();
528 // Get the global subtarget to output module-level info.
529 ST
= static_cast<const SPIRVTargetMachine
&>(TM
).getSubtargetImpl();
530 TII
= ST
->getInstrInfo();
531 MAI
= &SPIRVModuleAnalysis::MAI
;
532 assert(ST
&& TII
&& MAI
&& M
&& "Module analysis is required");
533 // Output instructions according to the Logical Layout of a Module:
534 // 1,2. All OpCapability instructions, then optional OpExtension instructions.
535 outputGlobalRequirements();
536 // 3. Optional OpExtInstImport instructions.
537 outputOpExtInstImports(*M
);
538 // 4. The single required OpMemoryModel instruction.
539 outputOpMemoryModel();
540 // 5. All entry point declarations, using OpEntryPoint.
542 // 6. Execution-mode declarations, using OpExecutionMode or OpExecutionModeId.
543 outputExecutionMode(*M
);
544 // 7a. Debug: all OpString, OpSourceExtension, OpSource, and
545 // OpSourceContinued, without forward references.
546 outputDebugSourceAndStrings(*M
);
547 // 7b. Debug: all OpName and all OpMemberName.
548 outputModuleSection(SPIRV::MB_DebugNames
);
549 // 7c. Debug: all OpModuleProcessed instructions.
550 outputModuleSection(SPIRV::MB_DebugModuleProcessed
);
551 // 8. All annotation instructions (all decorations).
552 outputAnnotations(*M
);
553 // 9. All type declarations (OpTypeXXX instructions), all constant
554 // instructions, and all global variable declarations. This section is
555 // the first section to allow use of: OpLine and OpNoLine debug information;
556 // non-semantic instructions with OpExtInst.
557 outputModuleSection(SPIRV::MB_TypeConstVars
);
558 // 10. All function declarations (functions without a body).
559 outputExtFuncDecls();
560 // 11. All function definitions (functions with a body).
561 // This is done in regular function output.
564 bool SPIRVAsmPrinter::doInitialization(Module
&M
) {
565 ModuleSectionsEmitted
= false;
566 // We need to call the parent's one explicitly.
567 return AsmPrinter::doInitialization(M
);
570 // Force static initialization.
571 extern "C" LLVM_EXTERNAL_VISIBILITY
void LLVMInitializeSPIRVAsmPrinter() {
572 RegisterAsmPrinter
<SPIRVAsmPrinter
> X(getTheSPIRV32Target());
573 RegisterAsmPrinter
<SPIRVAsmPrinter
> Y(getTheSPIRV64Target());
574 RegisterAsmPrinter
<SPIRVAsmPrinter
> Z(getTheSPIRVLogicalTarget());