xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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