181ad6265SDimitry Andric //===-- SPIRVAsmPrinter.cpp - SPIR-V LLVM assembly writer ------*- C++ -*--===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric // 981ad6265SDimitry Andric // This file contains a printer that converts from our internal representation 1081ad6265SDimitry Andric // of machine-dependent LLVM code to the SPIR-V assembly language. 1181ad6265SDimitry Andric // 1281ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1381ad6265SDimitry Andric 1481ad6265SDimitry Andric #include "MCTargetDesc/SPIRVInstPrinter.h" 1581ad6265SDimitry Andric #include "SPIRV.h" 1681ad6265SDimitry Andric #include "SPIRVInstrInfo.h" 1781ad6265SDimitry Andric #include "SPIRVMCInstLower.h" 1881ad6265SDimitry Andric #include "SPIRVModuleAnalysis.h" 1981ad6265SDimitry Andric #include "SPIRVSubtarget.h" 2081ad6265SDimitry Andric #include "SPIRVTargetMachine.h" 2181ad6265SDimitry Andric #include "SPIRVUtils.h" 2281ad6265SDimitry Andric #include "TargetInfo/SPIRVTargetInfo.h" 2381ad6265SDimitry Andric #include "llvm/ADT/DenseMap.h" 24fcaf7f86SDimitry Andric #include "llvm/Analysis/ValueTracking.h" 2581ad6265SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h" 2681ad6265SDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h" 2781ad6265SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 2881ad6265SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 2981ad6265SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h" 3081ad6265SDimitry Andric #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" 3181ad6265SDimitry Andric #include "llvm/MC/MCAsmInfo.h" 3281ad6265SDimitry Andric #include "llvm/MC/MCInst.h" 3381ad6265SDimitry Andric #include "llvm/MC/MCStreamer.h" 3481ad6265SDimitry Andric #include "llvm/MC/MCSymbol.h" 3581ad6265SDimitry Andric #include "llvm/MC/TargetRegistry.h" 3681ad6265SDimitry Andric #include "llvm/Support/raw_ostream.h" 3781ad6265SDimitry Andric 3881ad6265SDimitry Andric using namespace llvm; 3981ad6265SDimitry Andric 4081ad6265SDimitry Andric #define DEBUG_TYPE "asm-printer" 4181ad6265SDimitry Andric 4281ad6265SDimitry Andric namespace { 4381ad6265SDimitry Andric class SPIRVAsmPrinter : public AsmPrinter { 4481ad6265SDimitry Andric public: 4581ad6265SDimitry Andric explicit SPIRVAsmPrinter(TargetMachine &TM, 4681ad6265SDimitry Andric std::unique_ptr<MCStreamer> Streamer) 4781ad6265SDimitry Andric : AsmPrinter(TM, std::move(Streamer)), ST(nullptr), TII(nullptr) {} 4881ad6265SDimitry Andric bool ModuleSectionsEmitted; 4981ad6265SDimitry Andric const SPIRVSubtarget *ST; 5081ad6265SDimitry Andric const SPIRVInstrInfo *TII; 5181ad6265SDimitry Andric 5281ad6265SDimitry Andric StringRef getPassName() const override { return "SPIRV Assembly Printer"; } 5381ad6265SDimitry Andric void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O); 5481ad6265SDimitry Andric bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 5581ad6265SDimitry Andric const char *ExtraCode, raw_ostream &O) override; 5681ad6265SDimitry Andric 5781ad6265SDimitry Andric void outputMCInst(MCInst &Inst); 5881ad6265SDimitry Andric void outputInstruction(const MachineInstr *MI); 5981ad6265SDimitry Andric void outputModuleSection(SPIRV::ModuleSectionType MSType); 60bdd1243dSDimitry Andric void outputGlobalRequirements(); 6181ad6265SDimitry Andric void outputEntryPoints(); 6281ad6265SDimitry Andric void outputDebugSourceAndStrings(const Module &M); 63fcaf7f86SDimitry Andric void outputOpExtInstImports(const Module &M); 6481ad6265SDimitry Andric void outputOpMemoryModel(); 6581ad6265SDimitry Andric void outputOpFunctionEnd(); 6681ad6265SDimitry Andric void outputExtFuncDecls(); 67fcaf7f86SDimitry Andric void outputExecutionModeFromMDNode(Register Reg, MDNode *Node, 68bdd1243dSDimitry Andric SPIRV::ExecutionMode::ExecutionMode EM); 69fcaf7f86SDimitry Andric void outputExecutionMode(const Module &M); 70fcaf7f86SDimitry Andric void outputAnnotations(const Module &M); 7181ad6265SDimitry Andric void outputModuleSections(); 7281ad6265SDimitry Andric 7381ad6265SDimitry Andric void emitInstruction(const MachineInstr *MI) override; 7481ad6265SDimitry Andric void emitFunctionEntryLabel() override {} 7581ad6265SDimitry Andric void emitFunctionHeader() override; 7681ad6265SDimitry Andric void emitFunctionBodyStart() override {} 7781ad6265SDimitry Andric void emitFunctionBodyEnd() override; 7881ad6265SDimitry Andric void emitBasicBlockStart(const MachineBasicBlock &MBB) override; 7981ad6265SDimitry Andric void emitBasicBlockEnd(const MachineBasicBlock &MBB) override {} 8081ad6265SDimitry Andric void emitGlobalVariable(const GlobalVariable *GV) override {} 8181ad6265SDimitry Andric void emitOpLabel(const MachineBasicBlock &MBB); 8281ad6265SDimitry Andric void emitEndOfAsmFile(Module &M) override; 8381ad6265SDimitry Andric bool doInitialization(Module &M) override; 8481ad6265SDimitry Andric 8581ad6265SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override; 8681ad6265SDimitry Andric SPIRV::ModuleAnalysisInfo *MAI; 8781ad6265SDimitry Andric }; 8881ad6265SDimitry Andric } // namespace 8981ad6265SDimitry Andric 9081ad6265SDimitry Andric void SPIRVAsmPrinter::getAnalysisUsage(AnalysisUsage &AU) const { 9181ad6265SDimitry Andric AU.addRequired<SPIRVModuleAnalysis>(); 9281ad6265SDimitry Andric AU.addPreserved<SPIRVModuleAnalysis>(); 9381ad6265SDimitry Andric AsmPrinter::getAnalysisUsage(AU); 9481ad6265SDimitry Andric } 9581ad6265SDimitry Andric 9681ad6265SDimitry Andric // If the module has no functions, we need output global info anyway. 9781ad6265SDimitry Andric void SPIRVAsmPrinter::emitEndOfAsmFile(Module &M) { 9881ad6265SDimitry Andric if (ModuleSectionsEmitted == false) { 9981ad6265SDimitry Andric outputModuleSections(); 10081ad6265SDimitry Andric ModuleSectionsEmitted = true; 10181ad6265SDimitry Andric } 10281ad6265SDimitry Andric } 10381ad6265SDimitry Andric 10481ad6265SDimitry Andric void SPIRVAsmPrinter::emitFunctionHeader() { 10581ad6265SDimitry Andric if (ModuleSectionsEmitted == false) { 10681ad6265SDimitry Andric outputModuleSections(); 10781ad6265SDimitry Andric ModuleSectionsEmitted = true; 10881ad6265SDimitry Andric } 10981ad6265SDimitry Andric // Get the subtarget from the current MachineFunction. 11081ad6265SDimitry Andric ST = &MF->getSubtarget<SPIRVSubtarget>(); 11181ad6265SDimitry Andric TII = ST->getInstrInfo(); 11281ad6265SDimitry Andric const Function &F = MF->getFunction(); 11381ad6265SDimitry Andric 11481ad6265SDimitry Andric if (isVerbose()) { 11581ad6265SDimitry Andric OutStreamer->getCommentOS() 11681ad6265SDimitry Andric << "-- Begin function " 11781ad6265SDimitry Andric << GlobalValue::dropLLVMManglingEscape(F.getName()) << '\n'; 11881ad6265SDimitry Andric } 11981ad6265SDimitry Andric 12081ad6265SDimitry Andric auto Section = getObjFileLowering().SectionForGlobal(&F, TM); 12181ad6265SDimitry Andric MF->setSection(Section); 12281ad6265SDimitry Andric } 12381ad6265SDimitry Andric 12481ad6265SDimitry Andric void SPIRVAsmPrinter::outputOpFunctionEnd() { 12581ad6265SDimitry Andric MCInst FunctionEndInst; 12681ad6265SDimitry Andric FunctionEndInst.setOpcode(SPIRV::OpFunctionEnd); 12781ad6265SDimitry Andric outputMCInst(FunctionEndInst); 12881ad6265SDimitry Andric } 12981ad6265SDimitry Andric 13081ad6265SDimitry Andric // Emit OpFunctionEnd at the end of MF and clear BBNumToRegMap. 13181ad6265SDimitry Andric void SPIRVAsmPrinter::emitFunctionBodyEnd() { 13281ad6265SDimitry Andric outputOpFunctionEnd(); 13381ad6265SDimitry Andric MAI->BBNumToRegMap.clear(); 13481ad6265SDimitry Andric } 13581ad6265SDimitry Andric 13681ad6265SDimitry Andric void SPIRVAsmPrinter::emitOpLabel(const MachineBasicBlock &MBB) { 13781ad6265SDimitry Andric MCInst LabelInst; 13881ad6265SDimitry Andric LabelInst.setOpcode(SPIRV::OpLabel); 13981ad6265SDimitry Andric LabelInst.addOperand(MCOperand::createReg(MAI->getOrCreateMBBRegister(MBB))); 14081ad6265SDimitry Andric outputMCInst(LabelInst); 14181ad6265SDimitry Andric } 14281ad6265SDimitry Andric 14381ad6265SDimitry Andric void SPIRVAsmPrinter::emitBasicBlockStart(const MachineBasicBlock &MBB) { 144*06c3fb27SDimitry Andric assert(!MBB.empty() && "MBB is empty!"); 145*06c3fb27SDimitry Andric 14681ad6265SDimitry Andric // If it's the first MBB in MF, it has OpFunction and OpFunctionParameter, so 14781ad6265SDimitry Andric // OpLabel should be output after them. 14881ad6265SDimitry Andric if (MBB.getNumber() == MF->front().getNumber()) { 14981ad6265SDimitry Andric for (const MachineInstr &MI : MBB) 15081ad6265SDimitry Andric if (MI.getOpcode() == SPIRV::OpFunction) 15181ad6265SDimitry Andric return; 15281ad6265SDimitry Andric // TODO: this case should be checked by the verifier. 15381ad6265SDimitry Andric report_fatal_error("OpFunction is expected in the front MBB of MF"); 15481ad6265SDimitry Andric } 15581ad6265SDimitry Andric emitOpLabel(MBB); 15681ad6265SDimitry Andric } 15781ad6265SDimitry Andric 15881ad6265SDimitry Andric void SPIRVAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, 15981ad6265SDimitry Andric raw_ostream &O) { 16081ad6265SDimitry Andric const MachineOperand &MO = MI->getOperand(OpNum); 16181ad6265SDimitry Andric 16281ad6265SDimitry Andric switch (MO.getType()) { 16381ad6265SDimitry Andric case MachineOperand::MO_Register: 16481ad6265SDimitry Andric O << SPIRVInstPrinter::getRegisterName(MO.getReg()); 16581ad6265SDimitry Andric break; 16681ad6265SDimitry Andric 16781ad6265SDimitry Andric case MachineOperand::MO_Immediate: 16881ad6265SDimitry Andric O << MO.getImm(); 16981ad6265SDimitry Andric break; 17081ad6265SDimitry Andric 17181ad6265SDimitry Andric case MachineOperand::MO_FPImmediate: 17281ad6265SDimitry Andric O << MO.getFPImm(); 17381ad6265SDimitry Andric break; 17481ad6265SDimitry Andric 17581ad6265SDimitry Andric case MachineOperand::MO_MachineBasicBlock: 17681ad6265SDimitry Andric O << *MO.getMBB()->getSymbol(); 17781ad6265SDimitry Andric break; 17881ad6265SDimitry Andric 17981ad6265SDimitry Andric case MachineOperand::MO_GlobalAddress: 18081ad6265SDimitry Andric O << *getSymbol(MO.getGlobal()); 18181ad6265SDimitry Andric break; 18281ad6265SDimitry Andric 18381ad6265SDimitry Andric case MachineOperand::MO_BlockAddress: { 18481ad6265SDimitry Andric MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress()); 18581ad6265SDimitry Andric O << BA->getName(); 18681ad6265SDimitry Andric break; 18781ad6265SDimitry Andric } 18881ad6265SDimitry Andric 18981ad6265SDimitry Andric case MachineOperand::MO_ExternalSymbol: 19081ad6265SDimitry Andric O << *GetExternalSymbolSymbol(MO.getSymbolName()); 19181ad6265SDimitry Andric break; 19281ad6265SDimitry Andric 19381ad6265SDimitry Andric case MachineOperand::MO_JumpTableIndex: 19481ad6265SDimitry Andric case MachineOperand::MO_ConstantPoolIndex: 19581ad6265SDimitry Andric default: 19681ad6265SDimitry Andric llvm_unreachable("<unknown operand type>"); 19781ad6265SDimitry Andric } 19881ad6265SDimitry Andric } 19981ad6265SDimitry Andric 20081ad6265SDimitry Andric bool SPIRVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 20181ad6265SDimitry Andric const char *ExtraCode, raw_ostream &O) { 20281ad6265SDimitry Andric if (ExtraCode && ExtraCode[0]) 20381ad6265SDimitry Andric return true; // Invalid instruction - SPIR-V does not have special modifiers 20481ad6265SDimitry Andric 20581ad6265SDimitry Andric printOperand(MI, OpNo, O); 20681ad6265SDimitry Andric return false; 20781ad6265SDimitry Andric } 20881ad6265SDimitry Andric 20981ad6265SDimitry Andric static bool isFuncOrHeaderInstr(const MachineInstr *MI, 21081ad6265SDimitry Andric const SPIRVInstrInfo *TII) { 21181ad6265SDimitry Andric return TII->isHeaderInstr(*MI) || MI->getOpcode() == SPIRV::OpFunction || 21281ad6265SDimitry Andric MI->getOpcode() == SPIRV::OpFunctionParameter; 21381ad6265SDimitry Andric } 21481ad6265SDimitry Andric 21581ad6265SDimitry Andric void SPIRVAsmPrinter::outputMCInst(MCInst &Inst) { 21681ad6265SDimitry Andric OutStreamer->emitInstruction(Inst, *OutContext.getSubtargetInfo()); 21781ad6265SDimitry Andric } 21881ad6265SDimitry Andric 21981ad6265SDimitry Andric void SPIRVAsmPrinter::outputInstruction(const MachineInstr *MI) { 22081ad6265SDimitry Andric SPIRVMCInstLower MCInstLowering; 22181ad6265SDimitry Andric MCInst TmpInst; 22281ad6265SDimitry Andric MCInstLowering.lower(MI, TmpInst, MAI); 22381ad6265SDimitry Andric outputMCInst(TmpInst); 22481ad6265SDimitry Andric } 22581ad6265SDimitry Andric 22681ad6265SDimitry Andric void SPIRVAsmPrinter::emitInstruction(const MachineInstr *MI) { 227753f127fSDimitry Andric SPIRV_MC::verifyInstructionPredicates(MI->getOpcode(), 228753f127fSDimitry Andric getSubtargetInfo().getFeatureBits()); 229753f127fSDimitry Andric 23081ad6265SDimitry Andric if (!MAI->getSkipEmission(MI)) 23181ad6265SDimitry Andric outputInstruction(MI); 23281ad6265SDimitry Andric 23381ad6265SDimitry Andric // Output OpLabel after OpFunction and OpFunctionParameter in the first MBB. 23481ad6265SDimitry Andric const MachineInstr *NextMI = MI->getNextNode(); 23581ad6265SDimitry Andric if (!MAI->hasMBBRegister(*MI->getParent()) && isFuncOrHeaderInstr(MI, TII) && 23681ad6265SDimitry Andric (!NextMI || !isFuncOrHeaderInstr(NextMI, TII))) { 23781ad6265SDimitry Andric assert(MI->getParent()->getNumber() == MF->front().getNumber() && 23881ad6265SDimitry Andric "OpFunction is not in the front MBB of MF"); 23981ad6265SDimitry Andric emitOpLabel(*MI->getParent()); 24081ad6265SDimitry Andric } 24181ad6265SDimitry Andric } 24281ad6265SDimitry Andric 24381ad6265SDimitry Andric void SPIRVAsmPrinter::outputModuleSection(SPIRV::ModuleSectionType MSType) { 24481ad6265SDimitry Andric for (MachineInstr *MI : MAI->getMSInstrs(MSType)) 24581ad6265SDimitry Andric outputInstruction(MI); 24681ad6265SDimitry Andric } 24781ad6265SDimitry Andric 24881ad6265SDimitry Andric void SPIRVAsmPrinter::outputDebugSourceAndStrings(const Module &M) { 249fcaf7f86SDimitry Andric // Output OpSourceExtensions. 250fcaf7f86SDimitry Andric for (auto &Str : MAI->SrcExt) { 251fcaf7f86SDimitry Andric MCInst Inst; 252fcaf7f86SDimitry Andric Inst.setOpcode(SPIRV::OpSourceExtension); 253fcaf7f86SDimitry Andric addStringImm(Str.first(), Inst); 254fcaf7f86SDimitry Andric outputMCInst(Inst); 255fcaf7f86SDimitry Andric } 25681ad6265SDimitry Andric // Output OpSource. 25781ad6265SDimitry Andric MCInst Inst; 25881ad6265SDimitry Andric Inst.setOpcode(SPIRV::OpSource); 25981ad6265SDimitry Andric Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(MAI->SrcLang))); 26081ad6265SDimitry Andric Inst.addOperand( 26181ad6265SDimitry Andric MCOperand::createImm(static_cast<unsigned>(MAI->SrcLangVersion))); 26281ad6265SDimitry Andric outputMCInst(Inst); 26381ad6265SDimitry Andric } 26481ad6265SDimitry Andric 265fcaf7f86SDimitry Andric void SPIRVAsmPrinter::outputOpExtInstImports(const Module &M) { 266fcaf7f86SDimitry Andric for (auto &CU : MAI->ExtInstSetMap) { 267fcaf7f86SDimitry Andric unsigned Set = CU.first; 268fcaf7f86SDimitry Andric Register Reg = CU.second; 269fcaf7f86SDimitry Andric MCInst Inst; 270fcaf7f86SDimitry Andric Inst.setOpcode(SPIRV::OpExtInstImport); 271fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createReg(Reg)); 272bdd1243dSDimitry Andric addStringImm(getExtInstSetName( 273bdd1243dSDimitry Andric static_cast<SPIRV::InstructionSet::InstructionSet>(Set)), 274fcaf7f86SDimitry Andric Inst); 275fcaf7f86SDimitry Andric outputMCInst(Inst); 276fcaf7f86SDimitry Andric } 277fcaf7f86SDimitry Andric } 278fcaf7f86SDimitry Andric 27981ad6265SDimitry Andric void SPIRVAsmPrinter::outputOpMemoryModel() { 28081ad6265SDimitry Andric MCInst Inst; 28181ad6265SDimitry Andric Inst.setOpcode(SPIRV::OpMemoryModel); 28281ad6265SDimitry Andric Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(MAI->Addr))); 28381ad6265SDimitry Andric Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(MAI->Mem))); 28481ad6265SDimitry Andric outputMCInst(Inst); 28581ad6265SDimitry Andric } 28681ad6265SDimitry Andric 28781ad6265SDimitry Andric // Before the OpEntryPoints' output, we need to add the entry point's 28881ad6265SDimitry Andric // interfaces. The interface is a list of IDs of global OpVariable instructions. 28981ad6265SDimitry Andric // These declare the set of global variables from a module that form 29081ad6265SDimitry Andric // the interface of this entry point. 29181ad6265SDimitry Andric void SPIRVAsmPrinter::outputEntryPoints() { 29281ad6265SDimitry Andric // Find all OpVariable IDs with required StorageClass. 29381ad6265SDimitry Andric DenseSet<Register> InterfaceIDs; 29481ad6265SDimitry Andric for (MachineInstr *MI : MAI->GlobalVarList) { 29581ad6265SDimitry Andric assert(MI->getOpcode() == SPIRV::OpVariable); 296bdd1243dSDimitry Andric auto SC = static_cast<SPIRV::StorageClass::StorageClass>( 297bdd1243dSDimitry Andric MI->getOperand(2).getImm()); 29881ad6265SDimitry Andric // Before version 1.4, the interface's storage classes are limited to 29981ad6265SDimitry Andric // the Input and Output storage classes. Starting with version 1.4, 30081ad6265SDimitry Andric // the interface's storage classes are all storage classes used in 30181ad6265SDimitry Andric // declaring all global variables referenced by the entry point call tree. 30281ad6265SDimitry Andric if (ST->getSPIRVVersion() >= 14 || SC == SPIRV::StorageClass::Input || 30381ad6265SDimitry Andric SC == SPIRV::StorageClass::Output) { 30481ad6265SDimitry Andric MachineFunction *MF = MI->getMF(); 30581ad6265SDimitry Andric Register Reg = MAI->getRegisterAlias(MF, MI->getOperand(0).getReg()); 30681ad6265SDimitry Andric InterfaceIDs.insert(Reg); 30781ad6265SDimitry Andric } 30881ad6265SDimitry Andric } 30981ad6265SDimitry Andric 31081ad6265SDimitry Andric // Output OpEntryPoints adding interface args to all of them. 31181ad6265SDimitry Andric for (MachineInstr *MI : MAI->getMSInstrs(SPIRV::MB_EntryPoints)) { 31281ad6265SDimitry Andric SPIRVMCInstLower MCInstLowering; 31381ad6265SDimitry Andric MCInst TmpInst; 31481ad6265SDimitry Andric MCInstLowering.lower(MI, TmpInst, MAI); 31581ad6265SDimitry Andric for (Register Reg : InterfaceIDs) { 31681ad6265SDimitry Andric assert(Reg.isValid()); 31781ad6265SDimitry Andric TmpInst.addOperand(MCOperand::createReg(Reg)); 31881ad6265SDimitry Andric } 31981ad6265SDimitry Andric outputMCInst(TmpInst); 32081ad6265SDimitry Andric } 32181ad6265SDimitry Andric } 32281ad6265SDimitry Andric 323bdd1243dSDimitry Andric // Create global OpCapability instructions for the required capabilities. 324bdd1243dSDimitry Andric void SPIRVAsmPrinter::outputGlobalRequirements() { 325bdd1243dSDimitry Andric // Abort here if not all requirements can be satisfied. 326bdd1243dSDimitry Andric MAI->Reqs.checkSatisfiable(*ST); 327bdd1243dSDimitry Andric 328bdd1243dSDimitry Andric for (const auto &Cap : MAI->Reqs.getMinimalCapabilities()) { 329bdd1243dSDimitry Andric MCInst Inst; 330bdd1243dSDimitry Andric Inst.setOpcode(SPIRV::OpCapability); 331bdd1243dSDimitry Andric Inst.addOperand(MCOperand::createImm(Cap)); 332bdd1243dSDimitry Andric outputMCInst(Inst); 333bdd1243dSDimitry Andric } 334bdd1243dSDimitry Andric 335bdd1243dSDimitry Andric // Generate the final OpExtensions with strings instead of enums. 336bdd1243dSDimitry Andric for (const auto &Ext : MAI->Reqs.getExtensions()) { 337bdd1243dSDimitry Andric MCInst Inst; 338bdd1243dSDimitry Andric Inst.setOpcode(SPIRV::OpExtension); 339bdd1243dSDimitry Andric addStringImm(getSymbolicOperandMnemonic( 340bdd1243dSDimitry Andric SPIRV::OperandCategory::ExtensionOperand, Ext), 341bdd1243dSDimitry Andric Inst); 342bdd1243dSDimitry Andric outputMCInst(Inst); 343bdd1243dSDimitry Andric } 344bdd1243dSDimitry Andric // TODO add a pseudo instr for version number. 345bdd1243dSDimitry Andric } 346bdd1243dSDimitry Andric 34781ad6265SDimitry Andric void SPIRVAsmPrinter::outputExtFuncDecls() { 34881ad6265SDimitry Andric // Insert OpFunctionEnd after each declaration. 34981ad6265SDimitry Andric SmallVectorImpl<MachineInstr *>::iterator 35081ad6265SDimitry Andric I = MAI->getMSInstrs(SPIRV::MB_ExtFuncDecls).begin(), 35181ad6265SDimitry Andric E = MAI->getMSInstrs(SPIRV::MB_ExtFuncDecls).end(); 35281ad6265SDimitry Andric for (; I != E; ++I) { 35381ad6265SDimitry Andric outputInstruction(*I); 35481ad6265SDimitry Andric if ((I + 1) == E || (*(I + 1))->getOpcode() == SPIRV::OpFunction) 35581ad6265SDimitry Andric outputOpFunctionEnd(); 35681ad6265SDimitry Andric } 35781ad6265SDimitry Andric } 35881ad6265SDimitry Andric 359fcaf7f86SDimitry Andric // Encode LLVM type by SPIR-V execution mode VecTypeHint. 360fcaf7f86SDimitry Andric static unsigned encodeVecTypeHint(Type *Ty) { 361fcaf7f86SDimitry Andric if (Ty->isHalfTy()) 362fcaf7f86SDimitry Andric return 4; 363fcaf7f86SDimitry Andric if (Ty->isFloatTy()) 364fcaf7f86SDimitry Andric return 5; 365fcaf7f86SDimitry Andric if (Ty->isDoubleTy()) 366fcaf7f86SDimitry Andric return 6; 367fcaf7f86SDimitry Andric if (IntegerType *IntTy = dyn_cast<IntegerType>(Ty)) { 368fcaf7f86SDimitry Andric switch (IntTy->getIntegerBitWidth()) { 369fcaf7f86SDimitry Andric case 8: 370fcaf7f86SDimitry Andric return 0; 371fcaf7f86SDimitry Andric case 16: 372fcaf7f86SDimitry Andric return 1; 373fcaf7f86SDimitry Andric case 32: 374fcaf7f86SDimitry Andric return 2; 375fcaf7f86SDimitry Andric case 64: 376fcaf7f86SDimitry Andric return 3; 377fcaf7f86SDimitry Andric default: 378fcaf7f86SDimitry Andric llvm_unreachable("invalid integer type"); 379fcaf7f86SDimitry Andric } 380fcaf7f86SDimitry Andric } 381fcaf7f86SDimitry Andric if (FixedVectorType *VecTy = dyn_cast<FixedVectorType>(Ty)) { 382fcaf7f86SDimitry Andric Type *EleTy = VecTy->getElementType(); 383fcaf7f86SDimitry Andric unsigned Size = VecTy->getNumElements(); 384fcaf7f86SDimitry Andric return Size << 16 | encodeVecTypeHint(EleTy); 385fcaf7f86SDimitry Andric } 386fcaf7f86SDimitry Andric llvm_unreachable("invalid type"); 387fcaf7f86SDimitry Andric } 388fcaf7f86SDimitry Andric 389fcaf7f86SDimitry Andric static void addOpsFromMDNode(MDNode *MDN, MCInst &Inst, 390fcaf7f86SDimitry Andric SPIRV::ModuleAnalysisInfo *MAI) { 391fcaf7f86SDimitry Andric for (const MDOperand &MDOp : MDN->operands()) { 392fcaf7f86SDimitry Andric if (auto *CMeta = dyn_cast<ConstantAsMetadata>(MDOp)) { 393fcaf7f86SDimitry Andric Constant *C = CMeta->getValue(); 394fcaf7f86SDimitry Andric if (ConstantInt *Const = dyn_cast<ConstantInt>(C)) { 395fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createImm(Const->getZExtValue())); 396fcaf7f86SDimitry Andric } else if (auto *CE = dyn_cast<Function>(C)) { 397bdd1243dSDimitry Andric Register FuncReg = MAI->getFuncReg(CE); 398fcaf7f86SDimitry Andric assert(FuncReg.isValid()); 399fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createReg(FuncReg)); 400fcaf7f86SDimitry Andric } 401fcaf7f86SDimitry Andric } 402fcaf7f86SDimitry Andric } 403fcaf7f86SDimitry Andric } 404fcaf7f86SDimitry Andric 405bdd1243dSDimitry Andric void SPIRVAsmPrinter::outputExecutionModeFromMDNode( 406bdd1243dSDimitry Andric Register Reg, MDNode *Node, SPIRV::ExecutionMode::ExecutionMode EM) { 407fcaf7f86SDimitry Andric MCInst Inst; 408fcaf7f86SDimitry Andric Inst.setOpcode(SPIRV::OpExecutionMode); 409fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createReg(Reg)); 410fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(EM))); 411fcaf7f86SDimitry Andric addOpsFromMDNode(Node, Inst, MAI); 412fcaf7f86SDimitry Andric outputMCInst(Inst); 413fcaf7f86SDimitry Andric } 414fcaf7f86SDimitry Andric 415fcaf7f86SDimitry Andric void SPIRVAsmPrinter::outputExecutionMode(const Module &M) { 416fcaf7f86SDimitry Andric NamedMDNode *Node = M.getNamedMetadata("spirv.ExecutionMode"); 417fcaf7f86SDimitry Andric if (Node) { 418fcaf7f86SDimitry Andric for (unsigned i = 0; i < Node->getNumOperands(); i++) { 419fcaf7f86SDimitry Andric MCInst Inst; 420fcaf7f86SDimitry Andric Inst.setOpcode(SPIRV::OpExecutionMode); 421fcaf7f86SDimitry Andric addOpsFromMDNode(cast<MDNode>(Node->getOperand(i)), Inst, MAI); 422fcaf7f86SDimitry Andric outputMCInst(Inst); 423fcaf7f86SDimitry Andric } 424fcaf7f86SDimitry Andric } 425fcaf7f86SDimitry Andric for (auto FI = M.begin(), E = M.end(); FI != E; ++FI) { 426fcaf7f86SDimitry Andric const Function &F = *FI; 427fcaf7f86SDimitry Andric if (F.isDeclaration()) 428fcaf7f86SDimitry Andric continue; 429bdd1243dSDimitry Andric Register FReg = MAI->getFuncReg(&F); 430fcaf7f86SDimitry Andric assert(FReg.isValid()); 431fcaf7f86SDimitry Andric if (MDNode *Node = F.getMetadata("reqd_work_group_size")) 432fcaf7f86SDimitry Andric outputExecutionModeFromMDNode(FReg, Node, 433fcaf7f86SDimitry Andric SPIRV::ExecutionMode::LocalSize); 434fcaf7f86SDimitry Andric if (MDNode *Node = F.getMetadata("work_group_size_hint")) 435fcaf7f86SDimitry Andric outputExecutionModeFromMDNode(FReg, Node, 436fcaf7f86SDimitry Andric SPIRV::ExecutionMode::LocalSizeHint); 437fcaf7f86SDimitry Andric if (MDNode *Node = F.getMetadata("intel_reqd_sub_group_size")) 438fcaf7f86SDimitry Andric outputExecutionModeFromMDNode(FReg, Node, 439fcaf7f86SDimitry Andric SPIRV::ExecutionMode::SubgroupSize); 440fcaf7f86SDimitry Andric if (MDNode *Node = F.getMetadata("vec_type_hint")) { 441fcaf7f86SDimitry Andric MCInst Inst; 442fcaf7f86SDimitry Andric Inst.setOpcode(SPIRV::OpExecutionMode); 443fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createReg(FReg)); 444fcaf7f86SDimitry Andric unsigned EM = static_cast<unsigned>(SPIRV::ExecutionMode::VecTypeHint); 445fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createImm(EM)); 446fcaf7f86SDimitry Andric unsigned TypeCode = encodeVecTypeHint(getMDOperandAsType(Node, 0)); 447fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createImm(TypeCode)); 448fcaf7f86SDimitry Andric outputMCInst(Inst); 449fcaf7f86SDimitry Andric } 450bdd1243dSDimitry Andric if (!M.getNamedMetadata("spirv.ExecutionMode") && 451bdd1243dSDimitry Andric !M.getNamedMetadata("opencl.enable.FP_CONTRACT")) { 452bdd1243dSDimitry Andric MCInst Inst; 453bdd1243dSDimitry Andric Inst.setOpcode(SPIRV::OpExecutionMode); 454bdd1243dSDimitry Andric Inst.addOperand(MCOperand::createReg(FReg)); 455bdd1243dSDimitry Andric unsigned EM = static_cast<unsigned>(SPIRV::ExecutionMode::ContractionOff); 456bdd1243dSDimitry Andric Inst.addOperand(MCOperand::createImm(EM)); 457bdd1243dSDimitry Andric outputMCInst(Inst); 458bdd1243dSDimitry Andric } 459fcaf7f86SDimitry Andric } 460fcaf7f86SDimitry Andric } 461fcaf7f86SDimitry Andric 462fcaf7f86SDimitry Andric void SPIRVAsmPrinter::outputAnnotations(const Module &M) { 463fcaf7f86SDimitry Andric outputModuleSection(SPIRV::MB_Annotations); 464fcaf7f86SDimitry Andric // Process llvm.global.annotations special global variable. 465fcaf7f86SDimitry Andric for (auto F = M.global_begin(), E = M.global_end(); F != E; ++F) { 466fcaf7f86SDimitry Andric if ((*F).getName() != "llvm.global.annotations") 467fcaf7f86SDimitry Andric continue; 468fcaf7f86SDimitry Andric const GlobalVariable *V = &(*F); 469fcaf7f86SDimitry Andric const ConstantArray *CA = cast<ConstantArray>(V->getOperand(0)); 470fcaf7f86SDimitry Andric for (Value *Op : CA->operands()) { 471fcaf7f86SDimitry Andric ConstantStruct *CS = cast<ConstantStruct>(Op); 472fcaf7f86SDimitry Andric // The first field of the struct contains a pointer to 473fcaf7f86SDimitry Andric // the annotated variable. 474fcaf7f86SDimitry Andric Value *AnnotatedVar = CS->getOperand(0)->stripPointerCasts(); 475fcaf7f86SDimitry Andric if (!isa<Function>(AnnotatedVar)) 476bdd1243dSDimitry Andric report_fatal_error("Unsupported value in llvm.global.annotations"); 477fcaf7f86SDimitry Andric Function *Func = cast<Function>(AnnotatedVar); 478bdd1243dSDimitry Andric Register Reg = MAI->getFuncReg(Func); 479fcaf7f86SDimitry Andric 480fcaf7f86SDimitry Andric // The second field contains a pointer to a global annotation string. 481fcaf7f86SDimitry Andric GlobalVariable *GV = 482fcaf7f86SDimitry Andric cast<GlobalVariable>(CS->getOperand(1)->stripPointerCasts()); 483fcaf7f86SDimitry Andric 484fcaf7f86SDimitry Andric StringRef AnnotationString; 485fcaf7f86SDimitry Andric getConstantStringInfo(GV, AnnotationString); 486fcaf7f86SDimitry Andric MCInst Inst; 487fcaf7f86SDimitry Andric Inst.setOpcode(SPIRV::OpDecorate); 488fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createReg(Reg)); 489fcaf7f86SDimitry Andric unsigned Dec = static_cast<unsigned>(SPIRV::Decoration::UserSemantic); 490fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createImm(Dec)); 491fcaf7f86SDimitry Andric addStringImm(AnnotationString, Inst); 492fcaf7f86SDimitry Andric outputMCInst(Inst); 493fcaf7f86SDimitry Andric } 494fcaf7f86SDimitry Andric } 495fcaf7f86SDimitry Andric } 496fcaf7f86SDimitry Andric 49781ad6265SDimitry Andric void SPIRVAsmPrinter::outputModuleSections() { 49881ad6265SDimitry Andric const Module *M = MMI->getModule(); 49981ad6265SDimitry Andric // Get the global subtarget to output module-level info. 50081ad6265SDimitry Andric ST = static_cast<const SPIRVTargetMachine &>(TM).getSubtargetImpl(); 50181ad6265SDimitry Andric TII = ST->getInstrInfo(); 50281ad6265SDimitry Andric MAI = &SPIRVModuleAnalysis::MAI; 50381ad6265SDimitry Andric assert(ST && TII && MAI && M && "Module analysis is required"); 50481ad6265SDimitry Andric // Output instructions according to the Logical Layout of a Module: 505bdd1243dSDimitry Andric // 1,2. All OpCapability instructions, then optional OpExtension instructions. 506bdd1243dSDimitry Andric outputGlobalRequirements(); 507fcaf7f86SDimitry Andric // 3. Optional OpExtInstImport instructions. 508fcaf7f86SDimitry Andric outputOpExtInstImports(*M); 50981ad6265SDimitry Andric // 4. The single required OpMemoryModel instruction. 51081ad6265SDimitry Andric outputOpMemoryModel(); 51181ad6265SDimitry Andric // 5. All entry point declarations, using OpEntryPoint. 51281ad6265SDimitry Andric outputEntryPoints(); 51381ad6265SDimitry Andric // 6. Execution-mode declarations, using OpExecutionMode or OpExecutionModeId. 514fcaf7f86SDimitry Andric outputExecutionMode(*M); 51581ad6265SDimitry Andric // 7a. Debug: all OpString, OpSourceExtension, OpSource, and 51681ad6265SDimitry Andric // OpSourceContinued, without forward references. 51781ad6265SDimitry Andric outputDebugSourceAndStrings(*M); 51881ad6265SDimitry Andric // 7b. Debug: all OpName and all OpMemberName. 51981ad6265SDimitry Andric outputModuleSection(SPIRV::MB_DebugNames); 52081ad6265SDimitry Andric // 7c. Debug: all OpModuleProcessed instructions. 52181ad6265SDimitry Andric outputModuleSection(SPIRV::MB_DebugModuleProcessed); 52281ad6265SDimitry Andric // 8. All annotation instructions (all decorations). 523fcaf7f86SDimitry Andric outputAnnotations(*M); 52481ad6265SDimitry Andric // 9. All type declarations (OpTypeXXX instructions), all constant 52581ad6265SDimitry Andric // instructions, and all global variable declarations. This section is 52681ad6265SDimitry Andric // the first section to allow use of: OpLine and OpNoLine debug information; 52781ad6265SDimitry Andric // non-semantic instructions with OpExtInst. 52881ad6265SDimitry Andric outputModuleSection(SPIRV::MB_TypeConstVars); 52981ad6265SDimitry Andric // 10. All function declarations (functions without a body). 53081ad6265SDimitry Andric outputExtFuncDecls(); 53181ad6265SDimitry Andric // 11. All function definitions (functions with a body). 53281ad6265SDimitry Andric // This is done in regular function output. 53381ad6265SDimitry Andric } 53481ad6265SDimitry Andric 53581ad6265SDimitry Andric bool SPIRVAsmPrinter::doInitialization(Module &M) { 53681ad6265SDimitry Andric ModuleSectionsEmitted = false; 53781ad6265SDimitry Andric // We need to call the parent's one explicitly. 53881ad6265SDimitry Andric return AsmPrinter::doInitialization(M); 53981ad6265SDimitry Andric } 54081ad6265SDimitry Andric 54181ad6265SDimitry Andric // Force static initialization. 54281ad6265SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVAsmPrinter() { 54381ad6265SDimitry Andric RegisterAsmPrinter<SPIRVAsmPrinter> X(getTheSPIRV32Target()); 54481ad6265SDimitry Andric RegisterAsmPrinter<SPIRVAsmPrinter> Y(getTheSPIRV64Target()); 54581ad6265SDimitry Andric } 546