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