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); 69*5f757f3fSDimitry Andric void outputExecutionModeFromNumthreadsAttribute( 70*5f757f3fSDimitry Andric const Register &Reg, const Attribute &Attr, 71*5f757f3fSDimitry Andric SPIRV::ExecutionMode::ExecutionMode EM); 72fcaf7f86SDimitry Andric void outputExecutionMode(const Module &M); 73fcaf7f86SDimitry Andric void outputAnnotations(const Module &M); 7481ad6265SDimitry Andric void outputModuleSections(); 7581ad6265SDimitry Andric 7681ad6265SDimitry Andric void emitInstruction(const MachineInstr *MI) override; 7781ad6265SDimitry Andric void emitFunctionEntryLabel() override {} 7881ad6265SDimitry Andric void emitFunctionHeader() override; 7981ad6265SDimitry Andric void emitFunctionBodyStart() override {} 8081ad6265SDimitry Andric void emitFunctionBodyEnd() override; 8181ad6265SDimitry Andric void emitBasicBlockStart(const MachineBasicBlock &MBB) override; 8281ad6265SDimitry Andric void emitBasicBlockEnd(const MachineBasicBlock &MBB) override {} 8381ad6265SDimitry Andric void emitGlobalVariable(const GlobalVariable *GV) override {} 8481ad6265SDimitry Andric void emitOpLabel(const MachineBasicBlock &MBB); 8581ad6265SDimitry Andric void emitEndOfAsmFile(Module &M) override; 8681ad6265SDimitry Andric bool doInitialization(Module &M) override; 8781ad6265SDimitry Andric 8881ad6265SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override; 8981ad6265SDimitry Andric SPIRV::ModuleAnalysisInfo *MAI; 9081ad6265SDimitry Andric }; 9181ad6265SDimitry Andric } // namespace 9281ad6265SDimitry Andric 9381ad6265SDimitry Andric void SPIRVAsmPrinter::getAnalysisUsage(AnalysisUsage &AU) const { 9481ad6265SDimitry Andric AU.addRequired<SPIRVModuleAnalysis>(); 9581ad6265SDimitry Andric AU.addPreserved<SPIRVModuleAnalysis>(); 9681ad6265SDimitry Andric AsmPrinter::getAnalysisUsage(AU); 9781ad6265SDimitry Andric } 9881ad6265SDimitry Andric 9981ad6265SDimitry Andric // If the module has no functions, we need output global info anyway. 10081ad6265SDimitry Andric void SPIRVAsmPrinter::emitEndOfAsmFile(Module &M) { 10181ad6265SDimitry Andric if (ModuleSectionsEmitted == false) { 10281ad6265SDimitry Andric outputModuleSections(); 10381ad6265SDimitry Andric ModuleSectionsEmitted = true; 10481ad6265SDimitry Andric } 10581ad6265SDimitry Andric } 10681ad6265SDimitry Andric 10781ad6265SDimitry Andric void SPIRVAsmPrinter::emitFunctionHeader() { 10881ad6265SDimitry Andric if (ModuleSectionsEmitted == false) { 10981ad6265SDimitry Andric outputModuleSections(); 11081ad6265SDimitry Andric ModuleSectionsEmitted = true; 11181ad6265SDimitry Andric } 11281ad6265SDimitry Andric // Get the subtarget from the current MachineFunction. 11381ad6265SDimitry Andric ST = &MF->getSubtarget<SPIRVSubtarget>(); 11481ad6265SDimitry Andric TII = ST->getInstrInfo(); 11581ad6265SDimitry Andric const Function &F = MF->getFunction(); 11681ad6265SDimitry Andric 11781ad6265SDimitry Andric if (isVerbose()) { 11881ad6265SDimitry Andric OutStreamer->getCommentOS() 11981ad6265SDimitry Andric << "-- Begin function " 12081ad6265SDimitry Andric << GlobalValue::dropLLVMManglingEscape(F.getName()) << '\n'; 12181ad6265SDimitry Andric } 12281ad6265SDimitry Andric 12381ad6265SDimitry Andric auto Section = getObjFileLowering().SectionForGlobal(&F, TM); 12481ad6265SDimitry Andric MF->setSection(Section); 12581ad6265SDimitry Andric } 12681ad6265SDimitry Andric 12781ad6265SDimitry Andric void SPIRVAsmPrinter::outputOpFunctionEnd() { 12881ad6265SDimitry Andric MCInst FunctionEndInst; 12981ad6265SDimitry Andric FunctionEndInst.setOpcode(SPIRV::OpFunctionEnd); 13081ad6265SDimitry Andric outputMCInst(FunctionEndInst); 13181ad6265SDimitry Andric } 13281ad6265SDimitry Andric 13381ad6265SDimitry Andric // Emit OpFunctionEnd at the end of MF and clear BBNumToRegMap. 13481ad6265SDimitry Andric void SPIRVAsmPrinter::emitFunctionBodyEnd() { 13581ad6265SDimitry Andric outputOpFunctionEnd(); 13681ad6265SDimitry Andric MAI->BBNumToRegMap.clear(); 13781ad6265SDimitry Andric } 13881ad6265SDimitry Andric 13981ad6265SDimitry Andric void SPIRVAsmPrinter::emitOpLabel(const MachineBasicBlock &MBB) { 14081ad6265SDimitry Andric MCInst LabelInst; 14181ad6265SDimitry Andric LabelInst.setOpcode(SPIRV::OpLabel); 14281ad6265SDimitry Andric LabelInst.addOperand(MCOperand::createReg(MAI->getOrCreateMBBRegister(MBB))); 14381ad6265SDimitry Andric outputMCInst(LabelInst); 14481ad6265SDimitry Andric } 14581ad6265SDimitry Andric 14681ad6265SDimitry Andric void SPIRVAsmPrinter::emitBasicBlockStart(const MachineBasicBlock &MBB) { 14706c3fb27SDimitry Andric assert(!MBB.empty() && "MBB is empty!"); 14806c3fb27SDimitry Andric 14981ad6265SDimitry Andric // If it's the first MBB in MF, it has OpFunction and OpFunctionParameter, so 15081ad6265SDimitry Andric // OpLabel should be output after them. 15181ad6265SDimitry Andric if (MBB.getNumber() == MF->front().getNumber()) { 15281ad6265SDimitry Andric for (const MachineInstr &MI : MBB) 15381ad6265SDimitry Andric if (MI.getOpcode() == SPIRV::OpFunction) 15481ad6265SDimitry Andric return; 15581ad6265SDimitry Andric // TODO: this case should be checked by the verifier. 15681ad6265SDimitry Andric report_fatal_error("OpFunction is expected in the front MBB of MF"); 15781ad6265SDimitry Andric } 15881ad6265SDimitry Andric emitOpLabel(MBB); 15981ad6265SDimitry Andric } 16081ad6265SDimitry Andric 16181ad6265SDimitry Andric void SPIRVAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, 16281ad6265SDimitry Andric raw_ostream &O) { 16381ad6265SDimitry Andric const MachineOperand &MO = MI->getOperand(OpNum); 16481ad6265SDimitry Andric 16581ad6265SDimitry Andric switch (MO.getType()) { 16681ad6265SDimitry Andric case MachineOperand::MO_Register: 16781ad6265SDimitry Andric O << SPIRVInstPrinter::getRegisterName(MO.getReg()); 16881ad6265SDimitry Andric break; 16981ad6265SDimitry Andric 17081ad6265SDimitry Andric case MachineOperand::MO_Immediate: 17181ad6265SDimitry Andric O << MO.getImm(); 17281ad6265SDimitry Andric break; 17381ad6265SDimitry Andric 17481ad6265SDimitry Andric case MachineOperand::MO_FPImmediate: 17581ad6265SDimitry Andric O << MO.getFPImm(); 17681ad6265SDimitry Andric break; 17781ad6265SDimitry Andric 17881ad6265SDimitry Andric case MachineOperand::MO_MachineBasicBlock: 17981ad6265SDimitry Andric O << *MO.getMBB()->getSymbol(); 18081ad6265SDimitry Andric break; 18181ad6265SDimitry Andric 18281ad6265SDimitry Andric case MachineOperand::MO_GlobalAddress: 18381ad6265SDimitry Andric O << *getSymbol(MO.getGlobal()); 18481ad6265SDimitry Andric break; 18581ad6265SDimitry Andric 18681ad6265SDimitry Andric case MachineOperand::MO_BlockAddress: { 18781ad6265SDimitry Andric MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress()); 18881ad6265SDimitry Andric O << BA->getName(); 18981ad6265SDimitry Andric break; 19081ad6265SDimitry Andric } 19181ad6265SDimitry Andric 19281ad6265SDimitry Andric case MachineOperand::MO_ExternalSymbol: 19381ad6265SDimitry Andric O << *GetExternalSymbolSymbol(MO.getSymbolName()); 19481ad6265SDimitry Andric break; 19581ad6265SDimitry Andric 19681ad6265SDimitry Andric case MachineOperand::MO_JumpTableIndex: 19781ad6265SDimitry Andric case MachineOperand::MO_ConstantPoolIndex: 19881ad6265SDimitry Andric default: 19981ad6265SDimitry Andric llvm_unreachable("<unknown operand type>"); 20081ad6265SDimitry Andric } 20181ad6265SDimitry Andric } 20281ad6265SDimitry Andric 20381ad6265SDimitry Andric bool SPIRVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 20481ad6265SDimitry Andric const char *ExtraCode, raw_ostream &O) { 20581ad6265SDimitry Andric if (ExtraCode && ExtraCode[0]) 20681ad6265SDimitry Andric return true; // Invalid instruction - SPIR-V does not have special modifiers 20781ad6265SDimitry Andric 20881ad6265SDimitry Andric printOperand(MI, OpNo, O); 20981ad6265SDimitry Andric return false; 21081ad6265SDimitry Andric } 21181ad6265SDimitry Andric 21281ad6265SDimitry Andric static bool isFuncOrHeaderInstr(const MachineInstr *MI, 21381ad6265SDimitry Andric const SPIRVInstrInfo *TII) { 21481ad6265SDimitry Andric return TII->isHeaderInstr(*MI) || MI->getOpcode() == SPIRV::OpFunction || 21581ad6265SDimitry Andric MI->getOpcode() == SPIRV::OpFunctionParameter; 21681ad6265SDimitry Andric } 21781ad6265SDimitry Andric 21881ad6265SDimitry Andric void SPIRVAsmPrinter::outputMCInst(MCInst &Inst) { 21981ad6265SDimitry Andric OutStreamer->emitInstruction(Inst, *OutContext.getSubtargetInfo()); 22081ad6265SDimitry Andric } 22181ad6265SDimitry Andric 22281ad6265SDimitry Andric void SPIRVAsmPrinter::outputInstruction(const MachineInstr *MI) { 22381ad6265SDimitry Andric SPIRVMCInstLower MCInstLowering; 22481ad6265SDimitry Andric MCInst TmpInst; 22581ad6265SDimitry Andric MCInstLowering.lower(MI, TmpInst, MAI); 22681ad6265SDimitry Andric outputMCInst(TmpInst); 22781ad6265SDimitry Andric } 22881ad6265SDimitry Andric 22981ad6265SDimitry Andric void SPIRVAsmPrinter::emitInstruction(const MachineInstr *MI) { 230753f127fSDimitry Andric SPIRV_MC::verifyInstructionPredicates(MI->getOpcode(), 231753f127fSDimitry Andric getSubtargetInfo().getFeatureBits()); 232753f127fSDimitry Andric 23381ad6265SDimitry Andric if (!MAI->getSkipEmission(MI)) 23481ad6265SDimitry Andric outputInstruction(MI); 23581ad6265SDimitry Andric 23681ad6265SDimitry Andric // Output OpLabel after OpFunction and OpFunctionParameter in the first MBB. 23781ad6265SDimitry Andric const MachineInstr *NextMI = MI->getNextNode(); 23881ad6265SDimitry Andric if (!MAI->hasMBBRegister(*MI->getParent()) && isFuncOrHeaderInstr(MI, TII) && 23981ad6265SDimitry Andric (!NextMI || !isFuncOrHeaderInstr(NextMI, TII))) { 24081ad6265SDimitry Andric assert(MI->getParent()->getNumber() == MF->front().getNumber() && 24181ad6265SDimitry Andric "OpFunction is not in the front MBB of MF"); 24281ad6265SDimitry Andric emitOpLabel(*MI->getParent()); 24381ad6265SDimitry Andric } 24481ad6265SDimitry Andric } 24581ad6265SDimitry Andric 24681ad6265SDimitry Andric void SPIRVAsmPrinter::outputModuleSection(SPIRV::ModuleSectionType MSType) { 24781ad6265SDimitry Andric for (MachineInstr *MI : MAI->getMSInstrs(MSType)) 24881ad6265SDimitry Andric outputInstruction(MI); 24981ad6265SDimitry Andric } 25081ad6265SDimitry Andric 25181ad6265SDimitry Andric void SPIRVAsmPrinter::outputDebugSourceAndStrings(const Module &M) { 252fcaf7f86SDimitry Andric // Output OpSourceExtensions. 253fcaf7f86SDimitry Andric for (auto &Str : MAI->SrcExt) { 254fcaf7f86SDimitry Andric MCInst Inst; 255fcaf7f86SDimitry Andric Inst.setOpcode(SPIRV::OpSourceExtension); 256fcaf7f86SDimitry Andric addStringImm(Str.first(), Inst); 257fcaf7f86SDimitry Andric outputMCInst(Inst); 258fcaf7f86SDimitry Andric } 25981ad6265SDimitry Andric // Output OpSource. 26081ad6265SDimitry Andric MCInst Inst; 26181ad6265SDimitry Andric Inst.setOpcode(SPIRV::OpSource); 26281ad6265SDimitry Andric Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(MAI->SrcLang))); 26381ad6265SDimitry Andric Inst.addOperand( 26481ad6265SDimitry Andric MCOperand::createImm(static_cast<unsigned>(MAI->SrcLangVersion))); 26581ad6265SDimitry Andric outputMCInst(Inst); 26681ad6265SDimitry Andric } 26781ad6265SDimitry Andric 268fcaf7f86SDimitry Andric void SPIRVAsmPrinter::outputOpExtInstImports(const Module &M) { 269fcaf7f86SDimitry Andric for (auto &CU : MAI->ExtInstSetMap) { 270fcaf7f86SDimitry Andric unsigned Set = CU.first; 271fcaf7f86SDimitry Andric Register Reg = CU.second; 272fcaf7f86SDimitry Andric MCInst Inst; 273fcaf7f86SDimitry Andric Inst.setOpcode(SPIRV::OpExtInstImport); 274fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createReg(Reg)); 275bdd1243dSDimitry Andric addStringImm(getExtInstSetName( 276bdd1243dSDimitry Andric static_cast<SPIRV::InstructionSet::InstructionSet>(Set)), 277fcaf7f86SDimitry Andric Inst); 278fcaf7f86SDimitry Andric outputMCInst(Inst); 279fcaf7f86SDimitry Andric } 280fcaf7f86SDimitry Andric } 281fcaf7f86SDimitry Andric 28281ad6265SDimitry Andric void SPIRVAsmPrinter::outputOpMemoryModel() { 28381ad6265SDimitry Andric MCInst Inst; 28481ad6265SDimitry Andric Inst.setOpcode(SPIRV::OpMemoryModel); 28581ad6265SDimitry Andric Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(MAI->Addr))); 28681ad6265SDimitry Andric Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(MAI->Mem))); 28781ad6265SDimitry Andric outputMCInst(Inst); 28881ad6265SDimitry Andric } 28981ad6265SDimitry Andric 29081ad6265SDimitry Andric // Before the OpEntryPoints' output, we need to add the entry point's 29181ad6265SDimitry Andric // interfaces. The interface is a list of IDs of global OpVariable instructions. 29281ad6265SDimitry Andric // These declare the set of global variables from a module that form 29381ad6265SDimitry Andric // the interface of this entry point. 29481ad6265SDimitry Andric void SPIRVAsmPrinter::outputEntryPoints() { 29581ad6265SDimitry Andric // Find all OpVariable IDs with required StorageClass. 29681ad6265SDimitry Andric DenseSet<Register> InterfaceIDs; 29781ad6265SDimitry Andric for (MachineInstr *MI : MAI->GlobalVarList) { 29881ad6265SDimitry Andric assert(MI->getOpcode() == SPIRV::OpVariable); 299bdd1243dSDimitry Andric auto SC = static_cast<SPIRV::StorageClass::StorageClass>( 300bdd1243dSDimitry Andric MI->getOperand(2).getImm()); 30181ad6265SDimitry Andric // Before version 1.4, the interface's storage classes are limited to 30281ad6265SDimitry Andric // the Input and Output storage classes. Starting with version 1.4, 30381ad6265SDimitry Andric // the interface's storage classes are all storage classes used in 30481ad6265SDimitry Andric // declaring all global variables referenced by the entry point call tree. 30581ad6265SDimitry Andric if (ST->getSPIRVVersion() >= 14 || SC == SPIRV::StorageClass::Input || 30681ad6265SDimitry Andric SC == SPIRV::StorageClass::Output) { 30781ad6265SDimitry Andric MachineFunction *MF = MI->getMF(); 30881ad6265SDimitry Andric Register Reg = MAI->getRegisterAlias(MF, MI->getOperand(0).getReg()); 30981ad6265SDimitry Andric InterfaceIDs.insert(Reg); 31081ad6265SDimitry Andric } 31181ad6265SDimitry Andric } 31281ad6265SDimitry Andric 31381ad6265SDimitry Andric // Output OpEntryPoints adding interface args to all of them. 31481ad6265SDimitry Andric for (MachineInstr *MI : MAI->getMSInstrs(SPIRV::MB_EntryPoints)) { 31581ad6265SDimitry Andric SPIRVMCInstLower MCInstLowering; 31681ad6265SDimitry Andric MCInst TmpInst; 31781ad6265SDimitry Andric MCInstLowering.lower(MI, TmpInst, MAI); 31881ad6265SDimitry Andric for (Register Reg : InterfaceIDs) { 31981ad6265SDimitry Andric assert(Reg.isValid()); 32081ad6265SDimitry Andric TmpInst.addOperand(MCOperand::createReg(Reg)); 32181ad6265SDimitry Andric } 32281ad6265SDimitry Andric outputMCInst(TmpInst); 32381ad6265SDimitry Andric } 32481ad6265SDimitry Andric } 32581ad6265SDimitry Andric 326bdd1243dSDimitry Andric // Create global OpCapability instructions for the required capabilities. 327bdd1243dSDimitry Andric void SPIRVAsmPrinter::outputGlobalRequirements() { 328bdd1243dSDimitry Andric // Abort here if not all requirements can be satisfied. 329bdd1243dSDimitry Andric MAI->Reqs.checkSatisfiable(*ST); 330bdd1243dSDimitry Andric 331bdd1243dSDimitry Andric for (const auto &Cap : MAI->Reqs.getMinimalCapabilities()) { 332bdd1243dSDimitry Andric MCInst Inst; 333bdd1243dSDimitry Andric Inst.setOpcode(SPIRV::OpCapability); 334bdd1243dSDimitry Andric Inst.addOperand(MCOperand::createImm(Cap)); 335bdd1243dSDimitry Andric outputMCInst(Inst); 336bdd1243dSDimitry Andric } 337bdd1243dSDimitry Andric 338bdd1243dSDimitry Andric // Generate the final OpExtensions with strings instead of enums. 339bdd1243dSDimitry Andric for (const auto &Ext : MAI->Reqs.getExtensions()) { 340bdd1243dSDimitry Andric MCInst Inst; 341bdd1243dSDimitry Andric Inst.setOpcode(SPIRV::OpExtension); 342bdd1243dSDimitry Andric addStringImm(getSymbolicOperandMnemonic( 343bdd1243dSDimitry Andric SPIRV::OperandCategory::ExtensionOperand, Ext), 344bdd1243dSDimitry Andric Inst); 345bdd1243dSDimitry Andric outputMCInst(Inst); 346bdd1243dSDimitry Andric } 347bdd1243dSDimitry Andric // TODO add a pseudo instr for version number. 348bdd1243dSDimitry Andric } 349bdd1243dSDimitry Andric 35081ad6265SDimitry Andric void SPIRVAsmPrinter::outputExtFuncDecls() { 35181ad6265SDimitry Andric // Insert OpFunctionEnd after each declaration. 35281ad6265SDimitry Andric SmallVectorImpl<MachineInstr *>::iterator 35381ad6265SDimitry Andric I = MAI->getMSInstrs(SPIRV::MB_ExtFuncDecls).begin(), 35481ad6265SDimitry Andric E = MAI->getMSInstrs(SPIRV::MB_ExtFuncDecls).end(); 35581ad6265SDimitry Andric for (; I != E; ++I) { 35681ad6265SDimitry Andric outputInstruction(*I); 35781ad6265SDimitry Andric if ((I + 1) == E || (*(I + 1))->getOpcode() == SPIRV::OpFunction) 35881ad6265SDimitry Andric outputOpFunctionEnd(); 35981ad6265SDimitry Andric } 36081ad6265SDimitry Andric } 36181ad6265SDimitry Andric 362fcaf7f86SDimitry Andric // Encode LLVM type by SPIR-V execution mode VecTypeHint. 363fcaf7f86SDimitry Andric static unsigned encodeVecTypeHint(Type *Ty) { 364fcaf7f86SDimitry Andric if (Ty->isHalfTy()) 365fcaf7f86SDimitry Andric return 4; 366fcaf7f86SDimitry Andric if (Ty->isFloatTy()) 367fcaf7f86SDimitry Andric return 5; 368fcaf7f86SDimitry Andric if (Ty->isDoubleTy()) 369fcaf7f86SDimitry Andric return 6; 370fcaf7f86SDimitry Andric if (IntegerType *IntTy = dyn_cast<IntegerType>(Ty)) { 371fcaf7f86SDimitry Andric switch (IntTy->getIntegerBitWidth()) { 372fcaf7f86SDimitry Andric case 8: 373fcaf7f86SDimitry Andric return 0; 374fcaf7f86SDimitry Andric case 16: 375fcaf7f86SDimitry Andric return 1; 376fcaf7f86SDimitry Andric case 32: 377fcaf7f86SDimitry Andric return 2; 378fcaf7f86SDimitry Andric case 64: 379fcaf7f86SDimitry Andric return 3; 380fcaf7f86SDimitry Andric default: 381fcaf7f86SDimitry Andric llvm_unreachable("invalid integer type"); 382fcaf7f86SDimitry Andric } 383fcaf7f86SDimitry Andric } 384fcaf7f86SDimitry Andric if (FixedVectorType *VecTy = dyn_cast<FixedVectorType>(Ty)) { 385fcaf7f86SDimitry Andric Type *EleTy = VecTy->getElementType(); 386fcaf7f86SDimitry Andric unsigned Size = VecTy->getNumElements(); 387fcaf7f86SDimitry Andric return Size << 16 | encodeVecTypeHint(EleTy); 388fcaf7f86SDimitry Andric } 389fcaf7f86SDimitry Andric llvm_unreachable("invalid type"); 390fcaf7f86SDimitry Andric } 391fcaf7f86SDimitry Andric 392fcaf7f86SDimitry Andric static void addOpsFromMDNode(MDNode *MDN, MCInst &Inst, 393fcaf7f86SDimitry Andric SPIRV::ModuleAnalysisInfo *MAI) { 394fcaf7f86SDimitry Andric for (const MDOperand &MDOp : MDN->operands()) { 395fcaf7f86SDimitry Andric if (auto *CMeta = dyn_cast<ConstantAsMetadata>(MDOp)) { 396fcaf7f86SDimitry Andric Constant *C = CMeta->getValue(); 397fcaf7f86SDimitry Andric if (ConstantInt *Const = dyn_cast<ConstantInt>(C)) { 398fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createImm(Const->getZExtValue())); 399fcaf7f86SDimitry Andric } else if (auto *CE = dyn_cast<Function>(C)) { 400bdd1243dSDimitry Andric Register FuncReg = MAI->getFuncReg(CE); 401fcaf7f86SDimitry Andric assert(FuncReg.isValid()); 402fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createReg(FuncReg)); 403fcaf7f86SDimitry Andric } 404fcaf7f86SDimitry Andric } 405fcaf7f86SDimitry Andric } 406fcaf7f86SDimitry Andric } 407fcaf7f86SDimitry Andric 408bdd1243dSDimitry Andric void SPIRVAsmPrinter::outputExecutionModeFromMDNode( 409bdd1243dSDimitry Andric Register Reg, MDNode *Node, SPIRV::ExecutionMode::ExecutionMode EM) { 410fcaf7f86SDimitry Andric MCInst Inst; 411fcaf7f86SDimitry Andric Inst.setOpcode(SPIRV::OpExecutionMode); 412fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createReg(Reg)); 413fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(EM))); 414fcaf7f86SDimitry Andric addOpsFromMDNode(Node, Inst, MAI); 415fcaf7f86SDimitry Andric outputMCInst(Inst); 416fcaf7f86SDimitry Andric } 417fcaf7f86SDimitry Andric 418*5f757f3fSDimitry Andric void SPIRVAsmPrinter::outputExecutionModeFromNumthreadsAttribute( 419*5f757f3fSDimitry Andric const Register &Reg, const Attribute &Attr, 420*5f757f3fSDimitry Andric SPIRV::ExecutionMode::ExecutionMode EM) { 421*5f757f3fSDimitry Andric assert(Attr.isValid() && "Function called with an invalid attribute."); 422*5f757f3fSDimitry Andric 423*5f757f3fSDimitry Andric MCInst Inst; 424*5f757f3fSDimitry Andric Inst.setOpcode(SPIRV::OpExecutionMode); 425*5f757f3fSDimitry Andric Inst.addOperand(MCOperand::createReg(Reg)); 426*5f757f3fSDimitry Andric Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(EM))); 427*5f757f3fSDimitry Andric 428*5f757f3fSDimitry Andric SmallVector<StringRef> NumThreads; 429*5f757f3fSDimitry Andric Attr.getValueAsString().split(NumThreads, ','); 430*5f757f3fSDimitry Andric assert(NumThreads.size() == 3 && "invalid numthreads"); 431*5f757f3fSDimitry Andric for (uint32_t i = 0; i < 3; ++i) { 432*5f757f3fSDimitry Andric uint32_t V; 433*5f757f3fSDimitry Andric [[maybe_unused]] bool Result = NumThreads[i].getAsInteger(10, V); 434*5f757f3fSDimitry Andric assert(!Result && "Failed to parse numthreads"); 435*5f757f3fSDimitry Andric Inst.addOperand(MCOperand::createImm(V)); 436*5f757f3fSDimitry Andric } 437*5f757f3fSDimitry Andric 438*5f757f3fSDimitry Andric outputMCInst(Inst); 439*5f757f3fSDimitry Andric } 440*5f757f3fSDimitry Andric 441fcaf7f86SDimitry Andric void SPIRVAsmPrinter::outputExecutionMode(const Module &M) { 442fcaf7f86SDimitry Andric NamedMDNode *Node = M.getNamedMetadata("spirv.ExecutionMode"); 443fcaf7f86SDimitry Andric if (Node) { 444fcaf7f86SDimitry Andric for (unsigned i = 0; i < Node->getNumOperands(); i++) { 445fcaf7f86SDimitry Andric MCInst Inst; 446fcaf7f86SDimitry Andric Inst.setOpcode(SPIRV::OpExecutionMode); 447fcaf7f86SDimitry Andric addOpsFromMDNode(cast<MDNode>(Node->getOperand(i)), Inst, MAI); 448fcaf7f86SDimitry Andric outputMCInst(Inst); 449fcaf7f86SDimitry Andric } 450fcaf7f86SDimitry Andric } 451fcaf7f86SDimitry Andric for (auto FI = M.begin(), E = M.end(); FI != E; ++FI) { 452fcaf7f86SDimitry Andric const Function &F = *FI; 453fcaf7f86SDimitry Andric if (F.isDeclaration()) 454fcaf7f86SDimitry Andric continue; 455bdd1243dSDimitry Andric Register FReg = MAI->getFuncReg(&F); 456fcaf7f86SDimitry Andric assert(FReg.isValid()); 457fcaf7f86SDimitry Andric if (MDNode *Node = F.getMetadata("reqd_work_group_size")) 458fcaf7f86SDimitry Andric outputExecutionModeFromMDNode(FReg, Node, 459fcaf7f86SDimitry Andric SPIRV::ExecutionMode::LocalSize); 460*5f757f3fSDimitry Andric if (Attribute Attr = F.getFnAttribute("hlsl.numthreads"); Attr.isValid()) 461*5f757f3fSDimitry Andric outputExecutionModeFromNumthreadsAttribute( 462*5f757f3fSDimitry Andric FReg, Attr, SPIRV::ExecutionMode::LocalSize); 463fcaf7f86SDimitry Andric if (MDNode *Node = F.getMetadata("work_group_size_hint")) 464fcaf7f86SDimitry Andric outputExecutionModeFromMDNode(FReg, Node, 465fcaf7f86SDimitry Andric SPIRV::ExecutionMode::LocalSizeHint); 466fcaf7f86SDimitry Andric if (MDNode *Node = F.getMetadata("intel_reqd_sub_group_size")) 467fcaf7f86SDimitry Andric outputExecutionModeFromMDNode(FReg, Node, 468fcaf7f86SDimitry Andric SPIRV::ExecutionMode::SubgroupSize); 469fcaf7f86SDimitry Andric if (MDNode *Node = F.getMetadata("vec_type_hint")) { 470fcaf7f86SDimitry Andric MCInst Inst; 471fcaf7f86SDimitry Andric Inst.setOpcode(SPIRV::OpExecutionMode); 472fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createReg(FReg)); 473fcaf7f86SDimitry Andric unsigned EM = static_cast<unsigned>(SPIRV::ExecutionMode::VecTypeHint); 474fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createImm(EM)); 475fcaf7f86SDimitry Andric unsigned TypeCode = encodeVecTypeHint(getMDOperandAsType(Node, 0)); 476fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createImm(TypeCode)); 477fcaf7f86SDimitry Andric outputMCInst(Inst); 478fcaf7f86SDimitry Andric } 479*5f757f3fSDimitry Andric if (ST->isOpenCLEnv() && !M.getNamedMetadata("spirv.ExecutionMode") && 480bdd1243dSDimitry Andric !M.getNamedMetadata("opencl.enable.FP_CONTRACT")) { 481bdd1243dSDimitry Andric MCInst Inst; 482bdd1243dSDimitry Andric Inst.setOpcode(SPIRV::OpExecutionMode); 483bdd1243dSDimitry Andric Inst.addOperand(MCOperand::createReg(FReg)); 484bdd1243dSDimitry Andric unsigned EM = static_cast<unsigned>(SPIRV::ExecutionMode::ContractionOff); 485bdd1243dSDimitry Andric Inst.addOperand(MCOperand::createImm(EM)); 486bdd1243dSDimitry Andric outputMCInst(Inst); 487bdd1243dSDimitry Andric } 488fcaf7f86SDimitry Andric } 489fcaf7f86SDimitry Andric } 490fcaf7f86SDimitry Andric 491fcaf7f86SDimitry Andric void SPIRVAsmPrinter::outputAnnotations(const Module &M) { 492fcaf7f86SDimitry Andric outputModuleSection(SPIRV::MB_Annotations); 493fcaf7f86SDimitry Andric // Process llvm.global.annotations special global variable. 494fcaf7f86SDimitry Andric for (auto F = M.global_begin(), E = M.global_end(); F != E; ++F) { 495fcaf7f86SDimitry Andric if ((*F).getName() != "llvm.global.annotations") 496fcaf7f86SDimitry Andric continue; 497fcaf7f86SDimitry Andric const GlobalVariable *V = &(*F); 498fcaf7f86SDimitry Andric const ConstantArray *CA = cast<ConstantArray>(V->getOperand(0)); 499fcaf7f86SDimitry Andric for (Value *Op : CA->operands()) { 500fcaf7f86SDimitry Andric ConstantStruct *CS = cast<ConstantStruct>(Op); 501fcaf7f86SDimitry Andric // The first field of the struct contains a pointer to 502fcaf7f86SDimitry Andric // the annotated variable. 503fcaf7f86SDimitry Andric Value *AnnotatedVar = CS->getOperand(0)->stripPointerCasts(); 504fcaf7f86SDimitry Andric if (!isa<Function>(AnnotatedVar)) 505bdd1243dSDimitry Andric report_fatal_error("Unsupported value in llvm.global.annotations"); 506fcaf7f86SDimitry Andric Function *Func = cast<Function>(AnnotatedVar); 507bdd1243dSDimitry Andric Register Reg = MAI->getFuncReg(Func); 508fcaf7f86SDimitry Andric 509fcaf7f86SDimitry Andric // The second field contains a pointer to a global annotation string. 510fcaf7f86SDimitry Andric GlobalVariable *GV = 511fcaf7f86SDimitry Andric cast<GlobalVariable>(CS->getOperand(1)->stripPointerCasts()); 512fcaf7f86SDimitry Andric 513fcaf7f86SDimitry Andric StringRef AnnotationString; 514fcaf7f86SDimitry Andric getConstantStringInfo(GV, AnnotationString); 515fcaf7f86SDimitry Andric MCInst Inst; 516fcaf7f86SDimitry Andric Inst.setOpcode(SPIRV::OpDecorate); 517fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createReg(Reg)); 518fcaf7f86SDimitry Andric unsigned Dec = static_cast<unsigned>(SPIRV::Decoration::UserSemantic); 519fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createImm(Dec)); 520fcaf7f86SDimitry Andric addStringImm(AnnotationString, Inst); 521fcaf7f86SDimitry Andric outputMCInst(Inst); 522fcaf7f86SDimitry Andric } 523fcaf7f86SDimitry Andric } 524fcaf7f86SDimitry Andric } 525fcaf7f86SDimitry Andric 52681ad6265SDimitry Andric void SPIRVAsmPrinter::outputModuleSections() { 52781ad6265SDimitry Andric const Module *M = MMI->getModule(); 52881ad6265SDimitry Andric // Get the global subtarget to output module-level info. 52981ad6265SDimitry Andric ST = static_cast<const SPIRVTargetMachine &>(TM).getSubtargetImpl(); 53081ad6265SDimitry Andric TII = ST->getInstrInfo(); 53181ad6265SDimitry Andric MAI = &SPIRVModuleAnalysis::MAI; 53281ad6265SDimitry Andric assert(ST && TII && MAI && M && "Module analysis is required"); 53381ad6265SDimitry Andric // Output instructions according to the Logical Layout of a Module: 534bdd1243dSDimitry Andric // 1,2. All OpCapability instructions, then optional OpExtension instructions. 535bdd1243dSDimitry Andric outputGlobalRequirements(); 536fcaf7f86SDimitry Andric // 3. Optional OpExtInstImport instructions. 537fcaf7f86SDimitry Andric outputOpExtInstImports(*M); 53881ad6265SDimitry Andric // 4. The single required OpMemoryModel instruction. 53981ad6265SDimitry Andric outputOpMemoryModel(); 54081ad6265SDimitry Andric // 5. All entry point declarations, using OpEntryPoint. 54181ad6265SDimitry Andric outputEntryPoints(); 54281ad6265SDimitry Andric // 6. Execution-mode declarations, using OpExecutionMode or OpExecutionModeId. 543fcaf7f86SDimitry Andric outputExecutionMode(*M); 54481ad6265SDimitry Andric // 7a. Debug: all OpString, OpSourceExtension, OpSource, and 54581ad6265SDimitry Andric // OpSourceContinued, without forward references. 54681ad6265SDimitry Andric outputDebugSourceAndStrings(*M); 54781ad6265SDimitry Andric // 7b. Debug: all OpName and all OpMemberName. 54881ad6265SDimitry Andric outputModuleSection(SPIRV::MB_DebugNames); 54981ad6265SDimitry Andric // 7c. Debug: all OpModuleProcessed instructions. 55081ad6265SDimitry Andric outputModuleSection(SPIRV::MB_DebugModuleProcessed); 55181ad6265SDimitry Andric // 8. All annotation instructions (all decorations). 552fcaf7f86SDimitry Andric outputAnnotations(*M); 55381ad6265SDimitry Andric // 9. All type declarations (OpTypeXXX instructions), all constant 55481ad6265SDimitry Andric // instructions, and all global variable declarations. This section is 55581ad6265SDimitry Andric // the first section to allow use of: OpLine and OpNoLine debug information; 55681ad6265SDimitry Andric // non-semantic instructions with OpExtInst. 55781ad6265SDimitry Andric outputModuleSection(SPIRV::MB_TypeConstVars); 55881ad6265SDimitry Andric // 10. All function declarations (functions without a body). 55981ad6265SDimitry Andric outputExtFuncDecls(); 56081ad6265SDimitry Andric // 11. All function definitions (functions with a body). 56181ad6265SDimitry Andric // This is done in regular function output. 56281ad6265SDimitry Andric } 56381ad6265SDimitry Andric 56481ad6265SDimitry Andric bool SPIRVAsmPrinter::doInitialization(Module &M) { 56581ad6265SDimitry Andric ModuleSectionsEmitted = false; 56681ad6265SDimitry Andric // We need to call the parent's one explicitly. 56781ad6265SDimitry Andric return AsmPrinter::doInitialization(M); 56881ad6265SDimitry Andric } 56981ad6265SDimitry Andric 57081ad6265SDimitry Andric // Force static initialization. 57181ad6265SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVAsmPrinter() { 57281ad6265SDimitry Andric RegisterAsmPrinter<SPIRVAsmPrinter> X(getTheSPIRV32Target()); 57381ad6265SDimitry Andric RegisterAsmPrinter<SPIRVAsmPrinter> Y(getTheSPIRV64Target()); 574*5f757f3fSDimitry Andric RegisterAsmPrinter<SPIRVAsmPrinter> Z(getTheSPIRVLogicalTarget()); 57581ad6265SDimitry Andric } 576