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 "MCTargetDesc/SPIRVInstPrinter.h"
15 #include "SPIRV.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/CodeGen/AsmPrinter.h"
25 #include "llvm/CodeGen/MachineConstantPool.h"
26 #include "llvm/CodeGen/MachineFunctionPass.h"
27 #include "llvm/CodeGen/MachineInstr.h"
28 #include "llvm/CodeGen/MachineModuleInfo.h"
29 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
30 #include "llvm/MC/MCAsmInfo.h"
31 #include "llvm/MC/MCInst.h"
32 #include "llvm/MC/MCStreamer.h"
33 #include "llvm/MC/MCSymbol.h"
34 #include "llvm/MC/TargetRegistry.h"
35 #include "llvm/Support/raw_ostream.h"
36 
37 using namespace llvm;
38 
39 #define DEBUG_TYPE "asm-printer"
40 
41 namespace {
42 class SPIRVAsmPrinter : public AsmPrinter {
43 public:
44   explicit SPIRVAsmPrinter(TargetMachine &TM,
45                            std::unique_ptr<MCStreamer> Streamer)
46       : AsmPrinter(TM, std::move(Streamer)), ST(nullptr), TII(nullptr) {}
47   bool ModuleSectionsEmitted;
48   const SPIRVSubtarget *ST;
49   const SPIRVInstrInfo *TII;
50 
51   StringRef getPassName() const override { return "SPIRV Assembly Printer"; }
52   void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O);
53   bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
54                        const char *ExtraCode, raw_ostream &O) override;
55 
56   void outputMCInst(MCInst &Inst);
57   void outputInstruction(const MachineInstr *MI);
58   void outputModuleSection(SPIRV::ModuleSectionType MSType);
59   void outputEntryPoints();
60   void outputDebugSourceAndStrings(const Module &M);
61   void outputOpMemoryModel();
62   void outputOpFunctionEnd();
63   void outputExtFuncDecls();
64   void outputModuleSections();
65 
66   void emitInstruction(const MachineInstr *MI) override;
67   void emitFunctionEntryLabel() override {}
68   void emitFunctionHeader() override;
69   void emitFunctionBodyStart() override {}
70   void emitFunctionBodyEnd() override;
71   void emitBasicBlockStart(const MachineBasicBlock &MBB) override;
72   void emitBasicBlockEnd(const MachineBasicBlock &MBB) override {}
73   void emitGlobalVariable(const GlobalVariable *GV) override {}
74   void emitOpLabel(const MachineBasicBlock &MBB);
75   void emitEndOfAsmFile(Module &M) override;
76   bool doInitialization(Module &M) override;
77 
78   void getAnalysisUsage(AnalysisUsage &AU) const override;
79   SPIRV::ModuleAnalysisInfo *MAI;
80 };
81 } // namespace
82 
83 void SPIRVAsmPrinter::getAnalysisUsage(AnalysisUsage &AU) const {
84   AU.addRequired<SPIRVModuleAnalysis>();
85   AU.addPreserved<SPIRVModuleAnalysis>();
86   AsmPrinter::getAnalysisUsage(AU);
87 }
88 
89 // If the module has no functions, we need output global info anyway.
90 void SPIRVAsmPrinter::emitEndOfAsmFile(Module &M) {
91   if (ModuleSectionsEmitted == false) {
92     outputModuleSections();
93     ModuleSectionsEmitted = true;
94   }
95 }
96 
97 void SPIRVAsmPrinter::emitFunctionHeader() {
98   if (ModuleSectionsEmitted == false) {
99     outputModuleSections();
100     ModuleSectionsEmitted = true;
101   }
102   // Get the subtarget from the current MachineFunction.
103   ST = &MF->getSubtarget<SPIRVSubtarget>();
104   TII = ST->getInstrInfo();
105   const Function &F = MF->getFunction();
106 
107   if (isVerbose()) {
108     OutStreamer->getCommentOS()
109         << "-- Begin function "
110         << GlobalValue::dropLLVMManglingEscape(F.getName()) << '\n';
111   }
112 
113   auto Section = getObjFileLowering().SectionForGlobal(&F, TM);
114   MF->setSection(Section);
115 }
116 
117 void SPIRVAsmPrinter::outputOpFunctionEnd() {
118   MCInst FunctionEndInst;
119   FunctionEndInst.setOpcode(SPIRV::OpFunctionEnd);
120   outputMCInst(FunctionEndInst);
121 }
122 
123 // Emit OpFunctionEnd at the end of MF and clear BBNumToRegMap.
124 void SPIRVAsmPrinter::emitFunctionBodyEnd() {
125   outputOpFunctionEnd();
126   MAI->BBNumToRegMap.clear();
127 }
128 
129 void SPIRVAsmPrinter::emitOpLabel(const MachineBasicBlock &MBB) {
130   MCInst LabelInst;
131   LabelInst.setOpcode(SPIRV::OpLabel);
132   LabelInst.addOperand(MCOperand::createReg(MAI->getOrCreateMBBRegister(MBB)));
133   outputMCInst(LabelInst);
134 }
135 
136 void SPIRVAsmPrinter::emitBasicBlockStart(const MachineBasicBlock &MBB) {
137   // If it's the first MBB in MF, it has OpFunction and OpFunctionParameter, so
138   // OpLabel should be output after them.
139   if (MBB.getNumber() == MF->front().getNumber()) {
140     for (const MachineInstr &MI : MBB)
141       if (MI.getOpcode() == SPIRV::OpFunction)
142         return;
143     // TODO: this case should be checked by the verifier.
144     report_fatal_error("OpFunction is expected in the front MBB of MF");
145   }
146   emitOpLabel(MBB);
147 }
148 
149 void SPIRVAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
150                                    raw_ostream &O) {
151   const MachineOperand &MO = MI->getOperand(OpNum);
152 
153   switch (MO.getType()) {
154   case MachineOperand::MO_Register:
155     O << SPIRVInstPrinter::getRegisterName(MO.getReg());
156     break;
157 
158   case MachineOperand::MO_Immediate:
159     O << MO.getImm();
160     break;
161 
162   case MachineOperand::MO_FPImmediate:
163     O << MO.getFPImm();
164     break;
165 
166   case MachineOperand::MO_MachineBasicBlock:
167     O << *MO.getMBB()->getSymbol();
168     break;
169 
170   case MachineOperand::MO_GlobalAddress:
171     O << *getSymbol(MO.getGlobal());
172     break;
173 
174   case MachineOperand::MO_BlockAddress: {
175     MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress());
176     O << BA->getName();
177     break;
178   }
179 
180   case MachineOperand::MO_ExternalSymbol:
181     O << *GetExternalSymbolSymbol(MO.getSymbolName());
182     break;
183 
184   case MachineOperand::MO_JumpTableIndex:
185   case MachineOperand::MO_ConstantPoolIndex:
186   default:
187     llvm_unreachable("<unknown operand type>");
188   }
189 }
190 
191 bool SPIRVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
192                                       const char *ExtraCode, raw_ostream &O) {
193   if (ExtraCode && ExtraCode[0])
194     return true; // Invalid instruction - SPIR-V does not have special modifiers
195 
196   printOperand(MI, OpNo, O);
197   return false;
198 }
199 
200 static bool isFuncOrHeaderInstr(const MachineInstr *MI,
201                                 const SPIRVInstrInfo *TII) {
202   return TII->isHeaderInstr(*MI) || MI->getOpcode() == SPIRV::OpFunction ||
203          MI->getOpcode() == SPIRV::OpFunctionParameter;
204 }
205 
206 void SPIRVAsmPrinter::outputMCInst(MCInst &Inst) {
207   OutStreamer->emitInstruction(Inst, *OutContext.getSubtargetInfo());
208 }
209 
210 void SPIRVAsmPrinter::outputInstruction(const MachineInstr *MI) {
211   SPIRVMCInstLower MCInstLowering;
212   MCInst TmpInst;
213   MCInstLowering.lower(MI, TmpInst, MAI);
214   outputMCInst(TmpInst);
215 }
216 
217 void SPIRVAsmPrinter::emitInstruction(const MachineInstr *MI) {
218   if (!MAI->getSkipEmission(MI))
219     outputInstruction(MI);
220 
221   // Output OpLabel after OpFunction and OpFunctionParameter in the first MBB.
222   const MachineInstr *NextMI = MI->getNextNode();
223   if (!MAI->hasMBBRegister(*MI->getParent()) && isFuncOrHeaderInstr(MI, TII) &&
224       (!NextMI || !isFuncOrHeaderInstr(NextMI, TII))) {
225     assert(MI->getParent()->getNumber() == MF->front().getNumber() &&
226            "OpFunction is not in the front MBB of MF");
227     emitOpLabel(*MI->getParent());
228   }
229 }
230 
231 void SPIRVAsmPrinter::outputModuleSection(SPIRV::ModuleSectionType MSType) {
232   for (MachineInstr *MI : MAI->getMSInstrs(MSType))
233     outputInstruction(MI);
234 }
235 
236 void SPIRVAsmPrinter::outputDebugSourceAndStrings(const Module &M) {
237   // Output OpSource.
238   MCInst Inst;
239   Inst.setOpcode(SPIRV::OpSource);
240   Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(MAI->SrcLang)));
241   Inst.addOperand(
242       MCOperand::createImm(static_cast<unsigned>(MAI->SrcLangVersion)));
243   outputMCInst(Inst);
244 }
245 
246 void SPIRVAsmPrinter::outputOpMemoryModel() {
247   MCInst Inst;
248   Inst.setOpcode(SPIRV::OpMemoryModel);
249   Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(MAI->Addr)));
250   Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(MAI->Mem)));
251   outputMCInst(Inst);
252 }
253 
254 // Before the OpEntryPoints' output, we need to add the entry point's
255 // interfaces. The interface is a list of IDs of global OpVariable instructions.
256 // These declare the set of global variables from a module that form
257 // the interface of this entry point.
258 void SPIRVAsmPrinter::outputEntryPoints() {
259   // Find all OpVariable IDs with required StorageClass.
260   DenseSet<Register> InterfaceIDs;
261   for (MachineInstr *MI : MAI->GlobalVarList) {
262     assert(MI->getOpcode() == SPIRV::OpVariable);
263     auto SC = static_cast<SPIRV::StorageClass>(MI->getOperand(2).getImm());
264     // Before version 1.4, the interface's storage classes are limited to
265     // the Input and Output storage classes. Starting with version 1.4,
266     // the interface's storage classes are all storage classes used in
267     // declaring all global variables referenced by the entry point call tree.
268     if (ST->getSPIRVVersion() >= 14 || SC == SPIRV::StorageClass::Input ||
269         SC == SPIRV::StorageClass::Output) {
270       MachineFunction *MF = MI->getMF();
271       Register Reg = MAI->getRegisterAlias(MF, MI->getOperand(0).getReg());
272       InterfaceIDs.insert(Reg);
273     }
274   }
275 
276   // Output OpEntryPoints adding interface args to all of them.
277   for (MachineInstr *MI : MAI->getMSInstrs(SPIRV::MB_EntryPoints)) {
278     SPIRVMCInstLower MCInstLowering;
279     MCInst TmpInst;
280     MCInstLowering.lower(MI, TmpInst, MAI);
281     for (Register Reg : InterfaceIDs) {
282       assert(Reg.isValid());
283       TmpInst.addOperand(MCOperand::createReg(Reg));
284     }
285     outputMCInst(TmpInst);
286   }
287 }
288 
289 void SPIRVAsmPrinter::outputExtFuncDecls() {
290   // Insert OpFunctionEnd after each declaration.
291   SmallVectorImpl<MachineInstr *>::iterator
292       I = MAI->getMSInstrs(SPIRV::MB_ExtFuncDecls).begin(),
293       E = MAI->getMSInstrs(SPIRV::MB_ExtFuncDecls).end();
294   for (; I != E; ++I) {
295     outputInstruction(*I);
296     if ((I + 1) == E || (*(I + 1))->getOpcode() == SPIRV::OpFunction)
297       outputOpFunctionEnd();
298   }
299 }
300 
301 void SPIRVAsmPrinter::outputModuleSections() {
302   const Module *M = MMI->getModule();
303   // Get the global subtarget to output module-level info.
304   ST = static_cast<const SPIRVTargetMachine &>(TM).getSubtargetImpl();
305   TII = ST->getInstrInfo();
306   MAI = &SPIRVModuleAnalysis::MAI;
307   assert(ST && TII && MAI && M && "Module analysis is required");
308   // Output instructions according to the Logical Layout of a Module:
309   // TODO: 1,2. All OpCapability instructions, then optional OpExtension
310   // instructions.
311   // TODO: 3. Optional OpExtInstImport instructions.
312   // 4. The single required OpMemoryModel instruction.
313   outputOpMemoryModel();
314   // 5. All entry point declarations, using OpEntryPoint.
315   outputEntryPoints();
316   // 6. Execution-mode declarations, using OpExecutionMode or OpExecutionModeId.
317   // TODO:
318   // 7a. Debug: all OpString, OpSourceExtension, OpSource, and
319   // OpSourceContinued, without forward references.
320   outputDebugSourceAndStrings(*M);
321   // 7b. Debug: all OpName and all OpMemberName.
322   outputModuleSection(SPIRV::MB_DebugNames);
323   // 7c. Debug: all OpModuleProcessed instructions.
324   outputModuleSection(SPIRV::MB_DebugModuleProcessed);
325   // 8. All annotation instructions (all decorations).
326   outputModuleSection(SPIRV::MB_Annotations);
327   // 9. All type declarations (OpTypeXXX instructions), all constant
328   // instructions, and all global variable declarations. This section is
329   // the first section to allow use of: OpLine and OpNoLine debug information;
330   // non-semantic instructions with OpExtInst.
331   outputModuleSection(SPIRV::MB_TypeConstVars);
332   // 10. All function declarations (functions without a body).
333   outputExtFuncDecls();
334   // 11. All function definitions (functions with a body).
335   // This is done in regular function output.
336 }
337 
338 bool SPIRVAsmPrinter::doInitialization(Module &M) {
339   ModuleSectionsEmitted = false;
340   // We need to call the parent's one explicitly.
341   return AsmPrinter::doInitialization(M);
342 }
343 
344 // Force static initialization.
345 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVAsmPrinter() {
346   RegisterAsmPrinter<SPIRVAsmPrinter> X(getTheSPIRV32Target());
347   RegisterAsmPrinter<SPIRVAsmPrinter> Y(getTheSPIRV64Target());
348 }
349