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"
32*0fca6ea1SDimitry Andric #include "llvm/MC/MCAssembler.h"
3381ad6265SDimitry Andric #include "llvm/MC/MCInst.h"
34*0fca6ea1SDimitry Andric #include "llvm/MC/MCObjectStreamer.h"
35*0fca6ea1SDimitry Andric #include "llvm/MC/MCSPIRVObjectWriter.h"
3681ad6265SDimitry Andric #include "llvm/MC/MCStreamer.h"
3781ad6265SDimitry Andric #include "llvm/MC/MCSymbol.h"
3881ad6265SDimitry Andric #include "llvm/MC/TargetRegistry.h"
3981ad6265SDimitry Andric #include "llvm/Support/raw_ostream.h"
4081ad6265SDimitry Andric
4181ad6265SDimitry Andric using namespace llvm;
4281ad6265SDimitry Andric
4381ad6265SDimitry Andric #define DEBUG_TYPE "asm-printer"
4481ad6265SDimitry Andric
4581ad6265SDimitry Andric namespace {
4681ad6265SDimitry Andric class SPIRVAsmPrinter : public AsmPrinter {
47*0fca6ea1SDimitry Andric unsigned NLabels = 0;
48*0fca6ea1SDimitry Andric
4981ad6265SDimitry Andric public:
SPIRVAsmPrinter(TargetMachine & TM,std::unique_ptr<MCStreamer> Streamer)5081ad6265SDimitry Andric explicit SPIRVAsmPrinter(TargetMachine &TM,
5181ad6265SDimitry Andric std::unique_ptr<MCStreamer> Streamer)
5281ad6265SDimitry Andric : AsmPrinter(TM, std::move(Streamer)), ST(nullptr), TII(nullptr) {}
5381ad6265SDimitry Andric bool ModuleSectionsEmitted;
5481ad6265SDimitry Andric const SPIRVSubtarget *ST;
5581ad6265SDimitry Andric const SPIRVInstrInfo *TII;
5681ad6265SDimitry Andric
getPassName() const5781ad6265SDimitry Andric StringRef getPassName() const override { return "SPIRV Assembly Printer"; }
5881ad6265SDimitry Andric void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O);
5981ad6265SDimitry Andric bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
6081ad6265SDimitry Andric const char *ExtraCode, raw_ostream &O) override;
6181ad6265SDimitry Andric
6281ad6265SDimitry Andric void outputMCInst(MCInst &Inst);
6381ad6265SDimitry Andric void outputInstruction(const MachineInstr *MI);
6481ad6265SDimitry Andric void outputModuleSection(SPIRV::ModuleSectionType MSType);
65bdd1243dSDimitry Andric void outputGlobalRequirements();
6681ad6265SDimitry Andric void outputEntryPoints();
6781ad6265SDimitry Andric void outputDebugSourceAndStrings(const Module &M);
68fcaf7f86SDimitry Andric void outputOpExtInstImports(const Module &M);
6981ad6265SDimitry Andric void outputOpMemoryModel();
7081ad6265SDimitry Andric void outputOpFunctionEnd();
7181ad6265SDimitry Andric void outputExtFuncDecls();
72fcaf7f86SDimitry Andric void outputExecutionModeFromMDNode(Register Reg, MDNode *Node,
73*0fca6ea1SDimitry Andric SPIRV::ExecutionMode::ExecutionMode EM,
74*0fca6ea1SDimitry Andric unsigned ExpectMDOps, int64_t DefVal);
755f757f3fSDimitry Andric void outputExecutionModeFromNumthreadsAttribute(
765f757f3fSDimitry Andric const Register &Reg, const Attribute &Attr,
775f757f3fSDimitry Andric SPIRV::ExecutionMode::ExecutionMode EM);
78fcaf7f86SDimitry Andric void outputExecutionMode(const Module &M);
79fcaf7f86SDimitry Andric void outputAnnotations(const Module &M);
8081ad6265SDimitry Andric void outputModuleSections();
8181ad6265SDimitry Andric
8281ad6265SDimitry Andric void emitInstruction(const MachineInstr *MI) override;
emitFunctionEntryLabel()8381ad6265SDimitry Andric void emitFunctionEntryLabel() override {}
8481ad6265SDimitry Andric void emitFunctionHeader() override;
emitFunctionBodyStart()8581ad6265SDimitry Andric void emitFunctionBodyStart() override {}
8681ad6265SDimitry Andric void emitFunctionBodyEnd() override;
8781ad6265SDimitry Andric void emitBasicBlockStart(const MachineBasicBlock &MBB) override;
emitBasicBlockEnd(const MachineBasicBlock & MBB)8881ad6265SDimitry Andric void emitBasicBlockEnd(const MachineBasicBlock &MBB) override {}
emitGlobalVariable(const GlobalVariable * GV)8981ad6265SDimitry Andric void emitGlobalVariable(const GlobalVariable *GV) override {}
9081ad6265SDimitry Andric void emitOpLabel(const MachineBasicBlock &MBB);
9181ad6265SDimitry Andric void emitEndOfAsmFile(Module &M) override;
9281ad6265SDimitry Andric bool doInitialization(Module &M) override;
9381ad6265SDimitry Andric
9481ad6265SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override;
9581ad6265SDimitry Andric SPIRV::ModuleAnalysisInfo *MAI;
9681ad6265SDimitry Andric };
9781ad6265SDimitry Andric } // namespace
9881ad6265SDimitry Andric
getAnalysisUsage(AnalysisUsage & AU) const9981ad6265SDimitry Andric void SPIRVAsmPrinter::getAnalysisUsage(AnalysisUsage &AU) const {
10081ad6265SDimitry Andric AU.addRequired<SPIRVModuleAnalysis>();
10181ad6265SDimitry Andric AU.addPreserved<SPIRVModuleAnalysis>();
10281ad6265SDimitry Andric AsmPrinter::getAnalysisUsage(AU);
10381ad6265SDimitry Andric }
10481ad6265SDimitry Andric
10581ad6265SDimitry Andric // If the module has no functions, we need output global info anyway.
emitEndOfAsmFile(Module & M)10681ad6265SDimitry Andric void SPIRVAsmPrinter::emitEndOfAsmFile(Module &M) {
10781ad6265SDimitry Andric if (ModuleSectionsEmitted == false) {
10881ad6265SDimitry Andric outputModuleSections();
10981ad6265SDimitry Andric ModuleSectionsEmitted = true;
11081ad6265SDimitry Andric }
111*0fca6ea1SDimitry Andric
112*0fca6ea1SDimitry Andric ST = static_cast<const SPIRVTargetMachine &>(TM).getSubtargetImpl();
113*0fca6ea1SDimitry Andric VersionTuple SPIRVVersion = ST->getSPIRVVersion();
114*0fca6ea1SDimitry Andric uint32_t Major = SPIRVVersion.getMajor();
115*0fca6ea1SDimitry Andric uint32_t Minor = SPIRVVersion.getMinor().value_or(0);
116*0fca6ea1SDimitry Andric // Bound is an approximation that accounts for the maximum used register
117*0fca6ea1SDimitry Andric // number and number of generated OpLabels
118*0fca6ea1SDimitry Andric unsigned Bound = 2 * (ST->getBound() + 1) + NLabels;
119*0fca6ea1SDimitry Andric if (MCAssembler *Asm = OutStreamer->getAssemblerPtr())
120*0fca6ea1SDimitry Andric static_cast<SPIRVObjectWriter &>(Asm->getWriter())
121*0fca6ea1SDimitry Andric .setBuildVersion(Major, Minor, Bound);
12281ad6265SDimitry Andric }
12381ad6265SDimitry Andric
emitFunctionHeader()12481ad6265SDimitry Andric void SPIRVAsmPrinter::emitFunctionHeader() {
12581ad6265SDimitry Andric if (ModuleSectionsEmitted == false) {
12681ad6265SDimitry Andric outputModuleSections();
12781ad6265SDimitry Andric ModuleSectionsEmitted = true;
12881ad6265SDimitry Andric }
12981ad6265SDimitry Andric // Get the subtarget from the current MachineFunction.
13081ad6265SDimitry Andric ST = &MF->getSubtarget<SPIRVSubtarget>();
13181ad6265SDimitry Andric TII = ST->getInstrInfo();
13281ad6265SDimitry Andric const Function &F = MF->getFunction();
13381ad6265SDimitry Andric
13481ad6265SDimitry Andric if (isVerbose()) {
13581ad6265SDimitry Andric OutStreamer->getCommentOS()
13681ad6265SDimitry Andric << "-- Begin function "
13781ad6265SDimitry Andric << GlobalValue::dropLLVMManglingEscape(F.getName()) << '\n';
13881ad6265SDimitry Andric }
13981ad6265SDimitry Andric
14081ad6265SDimitry Andric auto Section = getObjFileLowering().SectionForGlobal(&F, TM);
14181ad6265SDimitry Andric MF->setSection(Section);
14281ad6265SDimitry Andric }
14381ad6265SDimitry Andric
outputOpFunctionEnd()14481ad6265SDimitry Andric void SPIRVAsmPrinter::outputOpFunctionEnd() {
14581ad6265SDimitry Andric MCInst FunctionEndInst;
14681ad6265SDimitry Andric FunctionEndInst.setOpcode(SPIRV::OpFunctionEnd);
14781ad6265SDimitry Andric outputMCInst(FunctionEndInst);
14881ad6265SDimitry Andric }
14981ad6265SDimitry Andric
15081ad6265SDimitry Andric // Emit OpFunctionEnd at the end of MF and clear BBNumToRegMap.
emitFunctionBodyEnd()15181ad6265SDimitry Andric void SPIRVAsmPrinter::emitFunctionBodyEnd() {
15281ad6265SDimitry Andric outputOpFunctionEnd();
15381ad6265SDimitry Andric MAI->BBNumToRegMap.clear();
15481ad6265SDimitry Andric }
15581ad6265SDimitry Andric
emitOpLabel(const MachineBasicBlock & MBB)15681ad6265SDimitry Andric void SPIRVAsmPrinter::emitOpLabel(const MachineBasicBlock &MBB) {
15781ad6265SDimitry Andric MCInst LabelInst;
15881ad6265SDimitry Andric LabelInst.setOpcode(SPIRV::OpLabel);
15981ad6265SDimitry Andric LabelInst.addOperand(MCOperand::createReg(MAI->getOrCreateMBBRegister(MBB)));
16081ad6265SDimitry Andric outputMCInst(LabelInst);
161*0fca6ea1SDimitry Andric ++NLabels;
16281ad6265SDimitry Andric }
16381ad6265SDimitry Andric
emitBasicBlockStart(const MachineBasicBlock & MBB)16481ad6265SDimitry Andric void SPIRVAsmPrinter::emitBasicBlockStart(const MachineBasicBlock &MBB) {
16506c3fb27SDimitry Andric assert(!MBB.empty() && "MBB is empty!");
16606c3fb27SDimitry Andric
16781ad6265SDimitry Andric // If it's the first MBB in MF, it has OpFunction and OpFunctionParameter, so
16881ad6265SDimitry Andric // OpLabel should be output after them.
16981ad6265SDimitry Andric if (MBB.getNumber() == MF->front().getNumber()) {
17081ad6265SDimitry Andric for (const MachineInstr &MI : MBB)
17181ad6265SDimitry Andric if (MI.getOpcode() == SPIRV::OpFunction)
17281ad6265SDimitry Andric return;
17381ad6265SDimitry Andric // TODO: this case should be checked by the verifier.
17481ad6265SDimitry Andric report_fatal_error("OpFunction is expected in the front MBB of MF");
17581ad6265SDimitry Andric }
17681ad6265SDimitry Andric emitOpLabel(MBB);
17781ad6265SDimitry Andric }
17881ad6265SDimitry Andric
printOperand(const MachineInstr * MI,int OpNum,raw_ostream & O)17981ad6265SDimitry Andric void SPIRVAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
18081ad6265SDimitry Andric raw_ostream &O) {
18181ad6265SDimitry Andric const MachineOperand &MO = MI->getOperand(OpNum);
18281ad6265SDimitry Andric
18381ad6265SDimitry Andric switch (MO.getType()) {
18481ad6265SDimitry Andric case MachineOperand::MO_Register:
18581ad6265SDimitry Andric O << SPIRVInstPrinter::getRegisterName(MO.getReg());
18681ad6265SDimitry Andric break;
18781ad6265SDimitry Andric
18881ad6265SDimitry Andric case MachineOperand::MO_Immediate:
18981ad6265SDimitry Andric O << MO.getImm();
19081ad6265SDimitry Andric break;
19181ad6265SDimitry Andric
19281ad6265SDimitry Andric case MachineOperand::MO_FPImmediate:
19381ad6265SDimitry Andric O << MO.getFPImm();
19481ad6265SDimitry Andric break;
19581ad6265SDimitry Andric
19681ad6265SDimitry Andric case MachineOperand::MO_MachineBasicBlock:
19781ad6265SDimitry Andric O << *MO.getMBB()->getSymbol();
19881ad6265SDimitry Andric break;
19981ad6265SDimitry Andric
20081ad6265SDimitry Andric case MachineOperand::MO_GlobalAddress:
20181ad6265SDimitry Andric O << *getSymbol(MO.getGlobal());
20281ad6265SDimitry Andric break;
20381ad6265SDimitry Andric
20481ad6265SDimitry Andric case MachineOperand::MO_BlockAddress: {
20581ad6265SDimitry Andric MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress());
20681ad6265SDimitry Andric O << BA->getName();
20781ad6265SDimitry Andric break;
20881ad6265SDimitry Andric }
20981ad6265SDimitry Andric
21081ad6265SDimitry Andric case MachineOperand::MO_ExternalSymbol:
21181ad6265SDimitry Andric O << *GetExternalSymbolSymbol(MO.getSymbolName());
21281ad6265SDimitry Andric break;
21381ad6265SDimitry Andric
21481ad6265SDimitry Andric case MachineOperand::MO_JumpTableIndex:
21581ad6265SDimitry Andric case MachineOperand::MO_ConstantPoolIndex:
21681ad6265SDimitry Andric default:
21781ad6265SDimitry Andric llvm_unreachable("<unknown operand type>");
21881ad6265SDimitry Andric }
21981ad6265SDimitry Andric }
22081ad6265SDimitry Andric
PrintAsmOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & O)22181ad6265SDimitry Andric bool SPIRVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
22281ad6265SDimitry Andric const char *ExtraCode, raw_ostream &O) {
22381ad6265SDimitry Andric if (ExtraCode && ExtraCode[0])
22481ad6265SDimitry Andric return true; // Invalid instruction - SPIR-V does not have special modifiers
22581ad6265SDimitry Andric
22681ad6265SDimitry Andric printOperand(MI, OpNo, O);
22781ad6265SDimitry Andric return false;
22881ad6265SDimitry Andric }
22981ad6265SDimitry Andric
isFuncOrHeaderInstr(const MachineInstr * MI,const SPIRVInstrInfo * TII)23081ad6265SDimitry Andric static bool isFuncOrHeaderInstr(const MachineInstr *MI,
23181ad6265SDimitry Andric const SPIRVInstrInfo *TII) {
23281ad6265SDimitry Andric return TII->isHeaderInstr(*MI) || MI->getOpcode() == SPIRV::OpFunction ||
23381ad6265SDimitry Andric MI->getOpcode() == SPIRV::OpFunctionParameter;
23481ad6265SDimitry Andric }
23581ad6265SDimitry Andric
outputMCInst(MCInst & Inst)23681ad6265SDimitry Andric void SPIRVAsmPrinter::outputMCInst(MCInst &Inst) {
23781ad6265SDimitry Andric OutStreamer->emitInstruction(Inst, *OutContext.getSubtargetInfo());
23881ad6265SDimitry Andric }
23981ad6265SDimitry Andric
outputInstruction(const MachineInstr * MI)24081ad6265SDimitry Andric void SPIRVAsmPrinter::outputInstruction(const MachineInstr *MI) {
24181ad6265SDimitry Andric SPIRVMCInstLower MCInstLowering;
24281ad6265SDimitry Andric MCInst TmpInst;
24381ad6265SDimitry Andric MCInstLowering.lower(MI, TmpInst, MAI);
24481ad6265SDimitry Andric outputMCInst(TmpInst);
24581ad6265SDimitry Andric }
24681ad6265SDimitry Andric
emitInstruction(const MachineInstr * MI)24781ad6265SDimitry Andric void SPIRVAsmPrinter::emitInstruction(const MachineInstr *MI) {
248753f127fSDimitry Andric SPIRV_MC::verifyInstructionPredicates(MI->getOpcode(),
249753f127fSDimitry Andric getSubtargetInfo().getFeatureBits());
250753f127fSDimitry Andric
25181ad6265SDimitry Andric if (!MAI->getSkipEmission(MI))
25281ad6265SDimitry Andric outputInstruction(MI);
25381ad6265SDimitry Andric
25481ad6265SDimitry Andric // Output OpLabel after OpFunction and OpFunctionParameter in the first MBB.
25581ad6265SDimitry Andric const MachineInstr *NextMI = MI->getNextNode();
25681ad6265SDimitry Andric if (!MAI->hasMBBRegister(*MI->getParent()) && isFuncOrHeaderInstr(MI, TII) &&
25781ad6265SDimitry Andric (!NextMI || !isFuncOrHeaderInstr(NextMI, TII))) {
25881ad6265SDimitry Andric assert(MI->getParent()->getNumber() == MF->front().getNumber() &&
25981ad6265SDimitry Andric "OpFunction is not in the front MBB of MF");
26081ad6265SDimitry Andric emitOpLabel(*MI->getParent());
26181ad6265SDimitry Andric }
26281ad6265SDimitry Andric }
26381ad6265SDimitry Andric
outputModuleSection(SPIRV::ModuleSectionType MSType)26481ad6265SDimitry Andric void SPIRVAsmPrinter::outputModuleSection(SPIRV::ModuleSectionType MSType) {
26581ad6265SDimitry Andric for (MachineInstr *MI : MAI->getMSInstrs(MSType))
26681ad6265SDimitry Andric outputInstruction(MI);
26781ad6265SDimitry Andric }
26881ad6265SDimitry Andric
outputDebugSourceAndStrings(const Module & M)26981ad6265SDimitry Andric void SPIRVAsmPrinter::outputDebugSourceAndStrings(const Module &M) {
270fcaf7f86SDimitry Andric // Output OpSourceExtensions.
271fcaf7f86SDimitry Andric for (auto &Str : MAI->SrcExt) {
272fcaf7f86SDimitry Andric MCInst Inst;
273fcaf7f86SDimitry Andric Inst.setOpcode(SPIRV::OpSourceExtension);
274fcaf7f86SDimitry Andric addStringImm(Str.first(), Inst);
275fcaf7f86SDimitry Andric outputMCInst(Inst);
276fcaf7f86SDimitry Andric }
27781ad6265SDimitry Andric // Output OpSource.
27881ad6265SDimitry Andric MCInst Inst;
27981ad6265SDimitry Andric Inst.setOpcode(SPIRV::OpSource);
28081ad6265SDimitry Andric Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(MAI->SrcLang)));
28181ad6265SDimitry Andric Inst.addOperand(
28281ad6265SDimitry Andric MCOperand::createImm(static_cast<unsigned>(MAI->SrcLangVersion)));
28381ad6265SDimitry Andric outputMCInst(Inst);
28481ad6265SDimitry Andric }
28581ad6265SDimitry Andric
outputOpExtInstImports(const Module & M)286fcaf7f86SDimitry Andric void SPIRVAsmPrinter::outputOpExtInstImports(const Module &M) {
287fcaf7f86SDimitry Andric for (auto &CU : MAI->ExtInstSetMap) {
288fcaf7f86SDimitry Andric unsigned Set = CU.first;
289fcaf7f86SDimitry Andric Register Reg = CU.second;
290fcaf7f86SDimitry Andric MCInst Inst;
291fcaf7f86SDimitry Andric Inst.setOpcode(SPIRV::OpExtInstImport);
292fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createReg(Reg));
293bdd1243dSDimitry Andric addStringImm(getExtInstSetName(
294bdd1243dSDimitry Andric static_cast<SPIRV::InstructionSet::InstructionSet>(Set)),
295fcaf7f86SDimitry Andric Inst);
296fcaf7f86SDimitry Andric outputMCInst(Inst);
297fcaf7f86SDimitry Andric }
298fcaf7f86SDimitry Andric }
299fcaf7f86SDimitry Andric
outputOpMemoryModel()30081ad6265SDimitry Andric void SPIRVAsmPrinter::outputOpMemoryModel() {
30181ad6265SDimitry Andric MCInst Inst;
30281ad6265SDimitry Andric Inst.setOpcode(SPIRV::OpMemoryModel);
30381ad6265SDimitry Andric Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(MAI->Addr)));
30481ad6265SDimitry Andric Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(MAI->Mem)));
30581ad6265SDimitry Andric outputMCInst(Inst);
30681ad6265SDimitry Andric }
30781ad6265SDimitry Andric
30881ad6265SDimitry Andric // Before the OpEntryPoints' output, we need to add the entry point's
30981ad6265SDimitry Andric // interfaces. The interface is a list of IDs of global OpVariable instructions.
31081ad6265SDimitry Andric // These declare the set of global variables from a module that form
31181ad6265SDimitry Andric // the interface of this entry point.
outputEntryPoints()31281ad6265SDimitry Andric void SPIRVAsmPrinter::outputEntryPoints() {
31381ad6265SDimitry Andric // Find all OpVariable IDs with required StorageClass.
31481ad6265SDimitry Andric DenseSet<Register> InterfaceIDs;
31581ad6265SDimitry Andric for (MachineInstr *MI : MAI->GlobalVarList) {
31681ad6265SDimitry Andric assert(MI->getOpcode() == SPIRV::OpVariable);
317bdd1243dSDimitry Andric auto SC = static_cast<SPIRV::StorageClass::StorageClass>(
318bdd1243dSDimitry Andric MI->getOperand(2).getImm());
31981ad6265SDimitry Andric // Before version 1.4, the interface's storage classes are limited to
32081ad6265SDimitry Andric // the Input and Output storage classes. Starting with version 1.4,
32181ad6265SDimitry Andric // the interface's storage classes are all storage classes used in
32281ad6265SDimitry Andric // declaring all global variables referenced by the entry point call tree.
323*0fca6ea1SDimitry Andric if (ST->isAtLeastSPIRVVer(VersionTuple(1, 4)) ||
324*0fca6ea1SDimitry Andric SC == SPIRV::StorageClass::Input || SC == SPIRV::StorageClass::Output) {
32581ad6265SDimitry Andric MachineFunction *MF = MI->getMF();
32681ad6265SDimitry Andric Register Reg = MAI->getRegisterAlias(MF, MI->getOperand(0).getReg());
32781ad6265SDimitry Andric InterfaceIDs.insert(Reg);
32881ad6265SDimitry Andric }
32981ad6265SDimitry Andric }
33081ad6265SDimitry Andric
33181ad6265SDimitry Andric // Output OpEntryPoints adding interface args to all of them.
33281ad6265SDimitry Andric for (MachineInstr *MI : MAI->getMSInstrs(SPIRV::MB_EntryPoints)) {
33381ad6265SDimitry Andric SPIRVMCInstLower MCInstLowering;
33481ad6265SDimitry Andric MCInst TmpInst;
33581ad6265SDimitry Andric MCInstLowering.lower(MI, TmpInst, MAI);
33681ad6265SDimitry Andric for (Register Reg : InterfaceIDs) {
33781ad6265SDimitry Andric assert(Reg.isValid());
33881ad6265SDimitry Andric TmpInst.addOperand(MCOperand::createReg(Reg));
33981ad6265SDimitry Andric }
34081ad6265SDimitry Andric outputMCInst(TmpInst);
34181ad6265SDimitry Andric }
34281ad6265SDimitry Andric }
34381ad6265SDimitry Andric
344bdd1243dSDimitry Andric // Create global OpCapability instructions for the required capabilities.
outputGlobalRequirements()345bdd1243dSDimitry Andric void SPIRVAsmPrinter::outputGlobalRequirements() {
346bdd1243dSDimitry Andric // Abort here if not all requirements can be satisfied.
347bdd1243dSDimitry Andric MAI->Reqs.checkSatisfiable(*ST);
348bdd1243dSDimitry Andric
349bdd1243dSDimitry Andric for (const auto &Cap : MAI->Reqs.getMinimalCapabilities()) {
350bdd1243dSDimitry Andric MCInst Inst;
351bdd1243dSDimitry Andric Inst.setOpcode(SPIRV::OpCapability);
352bdd1243dSDimitry Andric Inst.addOperand(MCOperand::createImm(Cap));
353bdd1243dSDimitry Andric outputMCInst(Inst);
354bdd1243dSDimitry Andric }
355bdd1243dSDimitry Andric
356bdd1243dSDimitry Andric // Generate the final OpExtensions with strings instead of enums.
357bdd1243dSDimitry Andric for (const auto &Ext : MAI->Reqs.getExtensions()) {
358bdd1243dSDimitry Andric MCInst Inst;
359bdd1243dSDimitry Andric Inst.setOpcode(SPIRV::OpExtension);
360bdd1243dSDimitry Andric addStringImm(getSymbolicOperandMnemonic(
361bdd1243dSDimitry Andric SPIRV::OperandCategory::ExtensionOperand, Ext),
362bdd1243dSDimitry Andric Inst);
363bdd1243dSDimitry Andric outputMCInst(Inst);
364bdd1243dSDimitry Andric }
365bdd1243dSDimitry Andric // TODO add a pseudo instr for version number.
366bdd1243dSDimitry Andric }
367bdd1243dSDimitry Andric
outputExtFuncDecls()36881ad6265SDimitry Andric void SPIRVAsmPrinter::outputExtFuncDecls() {
36981ad6265SDimitry Andric // Insert OpFunctionEnd after each declaration.
37081ad6265SDimitry Andric SmallVectorImpl<MachineInstr *>::iterator
37181ad6265SDimitry Andric I = MAI->getMSInstrs(SPIRV::MB_ExtFuncDecls).begin(),
37281ad6265SDimitry Andric E = MAI->getMSInstrs(SPIRV::MB_ExtFuncDecls).end();
37381ad6265SDimitry Andric for (; I != E; ++I) {
37481ad6265SDimitry Andric outputInstruction(*I);
37581ad6265SDimitry Andric if ((I + 1) == E || (*(I + 1))->getOpcode() == SPIRV::OpFunction)
37681ad6265SDimitry Andric outputOpFunctionEnd();
37781ad6265SDimitry Andric }
37881ad6265SDimitry Andric }
37981ad6265SDimitry Andric
380fcaf7f86SDimitry Andric // Encode LLVM type by SPIR-V execution mode VecTypeHint.
encodeVecTypeHint(Type * Ty)381fcaf7f86SDimitry Andric static unsigned encodeVecTypeHint(Type *Ty) {
382fcaf7f86SDimitry Andric if (Ty->isHalfTy())
383fcaf7f86SDimitry Andric return 4;
384fcaf7f86SDimitry Andric if (Ty->isFloatTy())
385fcaf7f86SDimitry Andric return 5;
386fcaf7f86SDimitry Andric if (Ty->isDoubleTy())
387fcaf7f86SDimitry Andric return 6;
388fcaf7f86SDimitry Andric if (IntegerType *IntTy = dyn_cast<IntegerType>(Ty)) {
389fcaf7f86SDimitry Andric switch (IntTy->getIntegerBitWidth()) {
390fcaf7f86SDimitry Andric case 8:
391fcaf7f86SDimitry Andric return 0;
392fcaf7f86SDimitry Andric case 16:
393fcaf7f86SDimitry Andric return 1;
394fcaf7f86SDimitry Andric case 32:
395fcaf7f86SDimitry Andric return 2;
396fcaf7f86SDimitry Andric case 64:
397fcaf7f86SDimitry Andric return 3;
398fcaf7f86SDimitry Andric default:
399fcaf7f86SDimitry Andric llvm_unreachable("invalid integer type");
400fcaf7f86SDimitry Andric }
401fcaf7f86SDimitry Andric }
402fcaf7f86SDimitry Andric if (FixedVectorType *VecTy = dyn_cast<FixedVectorType>(Ty)) {
403fcaf7f86SDimitry Andric Type *EleTy = VecTy->getElementType();
404fcaf7f86SDimitry Andric unsigned Size = VecTy->getNumElements();
405fcaf7f86SDimitry Andric return Size << 16 | encodeVecTypeHint(EleTy);
406fcaf7f86SDimitry Andric }
407fcaf7f86SDimitry Andric llvm_unreachable("invalid type");
408fcaf7f86SDimitry Andric }
409fcaf7f86SDimitry Andric
addOpsFromMDNode(MDNode * MDN,MCInst & Inst,SPIRV::ModuleAnalysisInfo * MAI)410fcaf7f86SDimitry Andric static void addOpsFromMDNode(MDNode *MDN, MCInst &Inst,
411fcaf7f86SDimitry Andric SPIRV::ModuleAnalysisInfo *MAI) {
412fcaf7f86SDimitry Andric for (const MDOperand &MDOp : MDN->operands()) {
413fcaf7f86SDimitry Andric if (auto *CMeta = dyn_cast<ConstantAsMetadata>(MDOp)) {
414fcaf7f86SDimitry Andric Constant *C = CMeta->getValue();
415fcaf7f86SDimitry Andric if (ConstantInt *Const = dyn_cast<ConstantInt>(C)) {
416fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createImm(Const->getZExtValue()));
417fcaf7f86SDimitry Andric } else if (auto *CE = dyn_cast<Function>(C)) {
418bdd1243dSDimitry Andric Register FuncReg = MAI->getFuncReg(CE);
419fcaf7f86SDimitry Andric assert(FuncReg.isValid());
420fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createReg(FuncReg));
421fcaf7f86SDimitry Andric }
422fcaf7f86SDimitry Andric }
423fcaf7f86SDimitry Andric }
424fcaf7f86SDimitry Andric }
425fcaf7f86SDimitry Andric
outputExecutionModeFromMDNode(Register Reg,MDNode * Node,SPIRV::ExecutionMode::ExecutionMode EM,unsigned ExpectMDOps,int64_t DefVal)426bdd1243dSDimitry Andric void SPIRVAsmPrinter::outputExecutionModeFromMDNode(
427*0fca6ea1SDimitry Andric Register Reg, MDNode *Node, SPIRV::ExecutionMode::ExecutionMode EM,
428*0fca6ea1SDimitry Andric unsigned ExpectMDOps, int64_t DefVal) {
429fcaf7f86SDimitry Andric MCInst Inst;
430fcaf7f86SDimitry Andric Inst.setOpcode(SPIRV::OpExecutionMode);
431fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createReg(Reg));
432fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(EM)));
433fcaf7f86SDimitry Andric addOpsFromMDNode(Node, Inst, MAI);
434*0fca6ea1SDimitry Andric // reqd_work_group_size and work_group_size_hint require 3 operands,
435*0fca6ea1SDimitry Andric // if metadata contains less operands, just add a default value
436*0fca6ea1SDimitry Andric unsigned NodeSz = Node->getNumOperands();
437*0fca6ea1SDimitry Andric if (ExpectMDOps > 0 && NodeSz < ExpectMDOps)
438*0fca6ea1SDimitry Andric for (unsigned i = NodeSz; i < ExpectMDOps; ++i)
439*0fca6ea1SDimitry Andric Inst.addOperand(MCOperand::createImm(DefVal));
440fcaf7f86SDimitry Andric outputMCInst(Inst);
441fcaf7f86SDimitry Andric }
442fcaf7f86SDimitry Andric
outputExecutionModeFromNumthreadsAttribute(const Register & Reg,const Attribute & Attr,SPIRV::ExecutionMode::ExecutionMode EM)4435f757f3fSDimitry Andric void SPIRVAsmPrinter::outputExecutionModeFromNumthreadsAttribute(
4445f757f3fSDimitry Andric const Register &Reg, const Attribute &Attr,
4455f757f3fSDimitry Andric SPIRV::ExecutionMode::ExecutionMode EM) {
4465f757f3fSDimitry Andric assert(Attr.isValid() && "Function called with an invalid attribute.");
4475f757f3fSDimitry Andric
4485f757f3fSDimitry Andric MCInst Inst;
4495f757f3fSDimitry Andric Inst.setOpcode(SPIRV::OpExecutionMode);
4505f757f3fSDimitry Andric Inst.addOperand(MCOperand::createReg(Reg));
4515f757f3fSDimitry Andric Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(EM)));
4525f757f3fSDimitry Andric
4535f757f3fSDimitry Andric SmallVector<StringRef> NumThreads;
4545f757f3fSDimitry Andric Attr.getValueAsString().split(NumThreads, ',');
4555f757f3fSDimitry Andric assert(NumThreads.size() == 3 && "invalid numthreads");
4565f757f3fSDimitry Andric for (uint32_t i = 0; i < 3; ++i) {
4575f757f3fSDimitry Andric uint32_t V;
4585f757f3fSDimitry Andric [[maybe_unused]] bool Result = NumThreads[i].getAsInteger(10, V);
4595f757f3fSDimitry Andric assert(!Result && "Failed to parse numthreads");
4605f757f3fSDimitry Andric Inst.addOperand(MCOperand::createImm(V));
4615f757f3fSDimitry Andric }
4625f757f3fSDimitry Andric
4635f757f3fSDimitry Andric outputMCInst(Inst);
4645f757f3fSDimitry Andric }
4655f757f3fSDimitry Andric
outputExecutionMode(const Module & M)466fcaf7f86SDimitry Andric void SPIRVAsmPrinter::outputExecutionMode(const Module &M) {
467fcaf7f86SDimitry Andric NamedMDNode *Node = M.getNamedMetadata("spirv.ExecutionMode");
468fcaf7f86SDimitry Andric if (Node) {
469fcaf7f86SDimitry Andric for (unsigned i = 0; i < Node->getNumOperands(); i++) {
470fcaf7f86SDimitry Andric MCInst Inst;
471fcaf7f86SDimitry Andric Inst.setOpcode(SPIRV::OpExecutionMode);
472fcaf7f86SDimitry Andric addOpsFromMDNode(cast<MDNode>(Node->getOperand(i)), Inst, MAI);
473fcaf7f86SDimitry Andric outputMCInst(Inst);
474fcaf7f86SDimitry Andric }
475fcaf7f86SDimitry Andric }
476fcaf7f86SDimitry Andric for (auto FI = M.begin(), E = M.end(); FI != E; ++FI) {
477fcaf7f86SDimitry Andric const Function &F = *FI;
478*0fca6ea1SDimitry Andric // Only operands of OpEntryPoint instructions are allowed to be
479*0fca6ea1SDimitry Andric // <Entry Point> operands of OpExecutionMode
480*0fca6ea1SDimitry Andric if (F.isDeclaration() || !isEntryPoint(F))
481fcaf7f86SDimitry Andric continue;
482bdd1243dSDimitry Andric Register FReg = MAI->getFuncReg(&F);
483fcaf7f86SDimitry Andric assert(FReg.isValid());
484fcaf7f86SDimitry Andric if (MDNode *Node = F.getMetadata("reqd_work_group_size"))
485*0fca6ea1SDimitry Andric outputExecutionModeFromMDNode(FReg, Node, SPIRV::ExecutionMode::LocalSize,
486*0fca6ea1SDimitry Andric 3, 1);
4875f757f3fSDimitry Andric if (Attribute Attr = F.getFnAttribute("hlsl.numthreads"); Attr.isValid())
4885f757f3fSDimitry Andric outputExecutionModeFromNumthreadsAttribute(
4895f757f3fSDimitry Andric FReg, Attr, SPIRV::ExecutionMode::LocalSize);
490fcaf7f86SDimitry Andric if (MDNode *Node = F.getMetadata("work_group_size_hint"))
491fcaf7f86SDimitry Andric outputExecutionModeFromMDNode(FReg, Node,
492*0fca6ea1SDimitry Andric SPIRV::ExecutionMode::LocalSizeHint, 3, 1);
493fcaf7f86SDimitry Andric if (MDNode *Node = F.getMetadata("intel_reqd_sub_group_size"))
494fcaf7f86SDimitry Andric outputExecutionModeFromMDNode(FReg, Node,
495*0fca6ea1SDimitry Andric SPIRV::ExecutionMode::SubgroupSize, 0, 0);
496fcaf7f86SDimitry Andric if (MDNode *Node = F.getMetadata("vec_type_hint")) {
497fcaf7f86SDimitry Andric MCInst Inst;
498fcaf7f86SDimitry Andric Inst.setOpcode(SPIRV::OpExecutionMode);
499fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createReg(FReg));
500fcaf7f86SDimitry Andric unsigned EM = static_cast<unsigned>(SPIRV::ExecutionMode::VecTypeHint);
501fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createImm(EM));
502fcaf7f86SDimitry Andric unsigned TypeCode = encodeVecTypeHint(getMDOperandAsType(Node, 0));
503fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createImm(TypeCode));
504fcaf7f86SDimitry Andric outputMCInst(Inst);
505fcaf7f86SDimitry Andric }
5065f757f3fSDimitry Andric if (ST->isOpenCLEnv() && !M.getNamedMetadata("spirv.ExecutionMode") &&
507bdd1243dSDimitry Andric !M.getNamedMetadata("opencl.enable.FP_CONTRACT")) {
508bdd1243dSDimitry Andric MCInst Inst;
509bdd1243dSDimitry Andric Inst.setOpcode(SPIRV::OpExecutionMode);
510bdd1243dSDimitry Andric Inst.addOperand(MCOperand::createReg(FReg));
511bdd1243dSDimitry Andric unsigned EM = static_cast<unsigned>(SPIRV::ExecutionMode::ContractionOff);
512bdd1243dSDimitry Andric Inst.addOperand(MCOperand::createImm(EM));
513bdd1243dSDimitry Andric outputMCInst(Inst);
514bdd1243dSDimitry Andric }
515fcaf7f86SDimitry Andric }
516fcaf7f86SDimitry Andric }
517fcaf7f86SDimitry Andric
outputAnnotations(const Module & M)518fcaf7f86SDimitry Andric void SPIRVAsmPrinter::outputAnnotations(const Module &M) {
519fcaf7f86SDimitry Andric outputModuleSection(SPIRV::MB_Annotations);
520fcaf7f86SDimitry Andric // Process llvm.global.annotations special global variable.
521fcaf7f86SDimitry Andric for (auto F = M.global_begin(), E = M.global_end(); F != E; ++F) {
522fcaf7f86SDimitry Andric if ((*F).getName() != "llvm.global.annotations")
523fcaf7f86SDimitry Andric continue;
524fcaf7f86SDimitry Andric const GlobalVariable *V = &(*F);
525fcaf7f86SDimitry Andric const ConstantArray *CA = cast<ConstantArray>(V->getOperand(0));
526fcaf7f86SDimitry Andric for (Value *Op : CA->operands()) {
527fcaf7f86SDimitry Andric ConstantStruct *CS = cast<ConstantStruct>(Op);
528fcaf7f86SDimitry Andric // The first field of the struct contains a pointer to
529fcaf7f86SDimitry Andric // the annotated variable.
530fcaf7f86SDimitry Andric Value *AnnotatedVar = CS->getOperand(0)->stripPointerCasts();
531fcaf7f86SDimitry Andric if (!isa<Function>(AnnotatedVar))
532bdd1243dSDimitry Andric report_fatal_error("Unsupported value in llvm.global.annotations");
533fcaf7f86SDimitry Andric Function *Func = cast<Function>(AnnotatedVar);
534bdd1243dSDimitry Andric Register Reg = MAI->getFuncReg(Func);
535*0fca6ea1SDimitry Andric if (!Reg.isValid()) {
536*0fca6ea1SDimitry Andric std::string DiagMsg;
537*0fca6ea1SDimitry Andric raw_string_ostream OS(DiagMsg);
538*0fca6ea1SDimitry Andric AnnotatedVar->print(OS);
539*0fca6ea1SDimitry Andric DiagMsg = "Unknown function in llvm.global.annotations: " + DiagMsg;
540*0fca6ea1SDimitry Andric report_fatal_error(DiagMsg.c_str());
541*0fca6ea1SDimitry Andric }
542fcaf7f86SDimitry Andric
543fcaf7f86SDimitry Andric // The second field contains a pointer to a global annotation string.
544fcaf7f86SDimitry Andric GlobalVariable *GV =
545fcaf7f86SDimitry Andric cast<GlobalVariable>(CS->getOperand(1)->stripPointerCasts());
546fcaf7f86SDimitry Andric
547fcaf7f86SDimitry Andric StringRef AnnotationString;
548fcaf7f86SDimitry Andric getConstantStringInfo(GV, AnnotationString);
549fcaf7f86SDimitry Andric MCInst Inst;
550fcaf7f86SDimitry Andric Inst.setOpcode(SPIRV::OpDecorate);
551fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createReg(Reg));
552fcaf7f86SDimitry Andric unsigned Dec = static_cast<unsigned>(SPIRV::Decoration::UserSemantic);
553fcaf7f86SDimitry Andric Inst.addOperand(MCOperand::createImm(Dec));
554fcaf7f86SDimitry Andric addStringImm(AnnotationString, Inst);
555fcaf7f86SDimitry Andric outputMCInst(Inst);
556fcaf7f86SDimitry Andric }
557fcaf7f86SDimitry Andric }
558fcaf7f86SDimitry Andric }
559fcaf7f86SDimitry Andric
outputModuleSections()56081ad6265SDimitry Andric void SPIRVAsmPrinter::outputModuleSections() {
56181ad6265SDimitry Andric const Module *M = MMI->getModule();
56281ad6265SDimitry Andric // Get the global subtarget to output module-level info.
56381ad6265SDimitry Andric ST = static_cast<const SPIRVTargetMachine &>(TM).getSubtargetImpl();
56481ad6265SDimitry Andric TII = ST->getInstrInfo();
56581ad6265SDimitry Andric MAI = &SPIRVModuleAnalysis::MAI;
56681ad6265SDimitry Andric assert(ST && TII && MAI && M && "Module analysis is required");
56781ad6265SDimitry Andric // Output instructions according to the Logical Layout of a Module:
568bdd1243dSDimitry Andric // 1,2. All OpCapability instructions, then optional OpExtension instructions.
569bdd1243dSDimitry Andric outputGlobalRequirements();
570fcaf7f86SDimitry Andric // 3. Optional OpExtInstImport instructions.
571fcaf7f86SDimitry Andric outputOpExtInstImports(*M);
57281ad6265SDimitry Andric // 4. The single required OpMemoryModel instruction.
57381ad6265SDimitry Andric outputOpMemoryModel();
57481ad6265SDimitry Andric // 5. All entry point declarations, using OpEntryPoint.
57581ad6265SDimitry Andric outputEntryPoints();
57681ad6265SDimitry Andric // 6. Execution-mode declarations, using OpExecutionMode or OpExecutionModeId.
577fcaf7f86SDimitry Andric outputExecutionMode(*M);
57881ad6265SDimitry Andric // 7a. Debug: all OpString, OpSourceExtension, OpSource, and
57981ad6265SDimitry Andric // OpSourceContinued, without forward references.
58081ad6265SDimitry Andric outputDebugSourceAndStrings(*M);
58181ad6265SDimitry Andric // 7b. Debug: all OpName and all OpMemberName.
58281ad6265SDimitry Andric outputModuleSection(SPIRV::MB_DebugNames);
58381ad6265SDimitry Andric // 7c. Debug: all OpModuleProcessed instructions.
58481ad6265SDimitry Andric outputModuleSection(SPIRV::MB_DebugModuleProcessed);
58581ad6265SDimitry Andric // 8. All annotation instructions (all decorations).
586fcaf7f86SDimitry Andric outputAnnotations(*M);
58781ad6265SDimitry Andric // 9. All type declarations (OpTypeXXX instructions), all constant
58881ad6265SDimitry Andric // instructions, and all global variable declarations. This section is
58981ad6265SDimitry Andric // the first section to allow use of: OpLine and OpNoLine debug information;
59081ad6265SDimitry Andric // non-semantic instructions with OpExtInst.
59181ad6265SDimitry Andric outputModuleSection(SPIRV::MB_TypeConstVars);
59281ad6265SDimitry Andric // 10. All function declarations (functions without a body).
59381ad6265SDimitry Andric outputExtFuncDecls();
59481ad6265SDimitry Andric // 11. All function definitions (functions with a body).
59581ad6265SDimitry Andric // This is done in regular function output.
59681ad6265SDimitry Andric }
59781ad6265SDimitry Andric
doInitialization(Module & M)59881ad6265SDimitry Andric bool SPIRVAsmPrinter::doInitialization(Module &M) {
59981ad6265SDimitry Andric ModuleSectionsEmitted = false;
60081ad6265SDimitry Andric // We need to call the parent's one explicitly.
60181ad6265SDimitry Andric return AsmPrinter::doInitialization(M);
60281ad6265SDimitry Andric }
60381ad6265SDimitry Andric
60481ad6265SDimitry Andric // Force static initialization.
LLVMInitializeSPIRVAsmPrinter()60581ad6265SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVAsmPrinter() {
60681ad6265SDimitry Andric RegisterAsmPrinter<SPIRVAsmPrinter> X(getTheSPIRV32Target());
60781ad6265SDimitry Andric RegisterAsmPrinter<SPIRVAsmPrinter> Y(getTheSPIRV64Target());
6085f757f3fSDimitry Andric RegisterAsmPrinter<SPIRVAsmPrinter> Z(getTheSPIRVLogicalTarget());
60981ad6265SDimitry Andric }
610