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