43#define DEBUG_TYPE "asm-printer"
52 std::unique_ptr<MCStreamer> Streamer)
53 :
AsmPrinter(TM, std::move(Streamer),
ID), ModuleSectionsEmitted(
false),
54 ST(
nullptr),
TII(
nullptr), MAI(
nullptr) {}
56 bool ModuleSectionsEmitted;
60 StringRef getPassName()
const override {
return "SPIRV Assembly Printer"; }
65 void outputMCInst(
MCInst &Inst);
68 void outputGlobalRequirements();
69 void outputEntryPoints();
70 void outputDebugSourceAndStrings(
const Module &M);
71 void outputOpExtInstImports(
const Module &M);
72 void outputOpMemoryModel();
73 void outputOpFunctionEnd();
74 void outputExtFuncDecls();
76 SPIRV::ExecutionMode::ExecutionMode EM,
77 unsigned ExpectMDOps, int64_t DefVal);
78 void outputExecutionModeFromNumthreadsAttribute(
80 SPIRV::ExecutionMode::ExecutionMode EM);
81 void outputExecutionMode(
const Module &M);
82 void outputAnnotations(
const Module &M);
83 void outputModuleSections();
85 return MF->getFunction()
91 void emitFunctionEntryLabel()
override {}
92 void emitFunctionHeader()
override;
93 void emitFunctionBodyStart()
override {}
94 void emitFunctionBodyEnd()
override;
99 void emitEndOfAsmFile(
Module &M)
override;
100 bool doInitialization(
Module &M)
override;
110void SPIRVAsmPrinter::getAnalysisUsage(
AnalysisUsage &AU)
const {
117void SPIRVAsmPrinter::emitEndOfAsmFile(
Module &M) {
118 if (ModuleSectionsEmitted ==
false) {
119 outputModuleSections();
120 ModuleSectionsEmitted =
true;
123 ST =
static_cast<const SPIRVTargetMachine &
>(
TM).getSubtargetImpl();
125 uint32_t Major = SPIRVVersion.
getMajor();
126 uint32_t Minor = SPIRVVersion.
getMinor().value_or(0);
129 unsigned Bound = 2 * (ST->
getBound() + 1) + NLabels;
130 if (MCAssembler *Asm = OutStreamer->getAssemblerPtr())
131 static_cast<SPIRVObjectWriter &
>(
Asm->getWriter())
132 .setBuildVersion(Major, Minor, Bound);
139void SPIRVAsmPrinter::cleanUp(
Module &M) {
141 for (StringRef GVName : {
"llvm.global_ctors",
"llvm.global_dtors",
142 "llvm.used",
"llvm.compiler.used"}) {
143 if (GlobalVariable *GV =
M.getNamedGlobal(GVName))
148void SPIRVAsmPrinter::emitFunctionHeader() {
149 if (ModuleSectionsEmitted ==
false) {
150 outputModuleSections();
151 ModuleSectionsEmitted =
true;
154 ST = &MF->getSubtarget<SPIRVSubtarget>();
158 if (isVerbose() && !isHidden()) {
159 OutStreamer->getCommentOS()
160 <<
"-- Begin function "
164 auto Section = getObjFileLowering().SectionForGlobal(&
F, TM);
165 MF->setSection(Section);
168void SPIRVAsmPrinter::outputOpFunctionEnd() {
169 MCInst FunctionEndInst;
170 FunctionEndInst.
setOpcode(SPIRV::OpFunctionEnd);
171 outputMCInst(FunctionEndInst);
174void SPIRVAsmPrinter::emitFunctionBodyEnd() {
176 outputOpFunctionEnd();
179void SPIRVAsmPrinter::emitOpLabel(
const MachineBasicBlock &
MBB) {
187 outputMCInst(LabelInst);
192void SPIRVAsmPrinter::emitBasicBlockStart(
const MachineBasicBlock &
MBB) {
200 for (
const MachineInstr &
MI :
MBB)
201 if (
MI.getOpcode() == SPIRV::OpFunction)
209void SPIRVAsmPrinter::printOperand(
const MachineInstr *
MI,
int OpNum,
211 const MachineOperand &MO =
MI->getOperand(OpNum);
251bool SPIRVAsmPrinter::PrintAsmOperand(
const MachineInstr *
MI,
unsigned OpNo,
252 const char *ExtraCode, raw_ostream &O) {
253 if (ExtraCode && ExtraCode[0])
262 return TII->isHeaderInstr(*
MI) ||
MI->getOpcode() == SPIRV::OpFunction ||
263 MI->getOpcode() == SPIRV::OpFunctionParameter;
266void SPIRVAsmPrinter::outputMCInst(MCInst &Inst) {
267 OutStreamer->emitInstruction(Inst, *OutContext.getSubtargetInfo());
270void SPIRVAsmPrinter::outputInstruction(
const MachineInstr *
MI) {
271 SPIRVMCInstLower MCInstLowering;
273 MCInstLowering.
lower(
MI, TmpInst, MAI);
274 outputMCInst(TmpInst);
277void SPIRVAsmPrinter::emitInstruction(
const MachineInstr *
MI) {
278 SPIRV_MC::verifyInstructionPredicates(
MI->getOpcode(),
279 getSubtargetInfo().getFeatureBits());
281 if (!MAI->getSkipEmission(
MI))
282 outputInstruction(
MI);
285 const MachineInstr *NextMI =
MI->getNextNode();
288 assert(
MI->getParent()->getNumber() == MF->front().getNumber() &&
289 "OpFunction is not in the front MBB of MF");
290 emitOpLabel(*
MI->getParent());
294void SPIRVAsmPrinter::outputModuleSection(SPIRV::ModuleSectionType MSType) {
295 for (
const MachineInstr *
MI : MAI->getMSInstrs(MSType))
296 outputInstruction(
MI);
299void SPIRVAsmPrinter::outputDebugSourceAndStrings(
const Module &M) {
301 for (
auto &Str : MAI->SrcExt) {
303 Inst.
setOpcode(SPIRV::OpSourceExtension);
308 outputModuleSection(SPIRV::MB_DebugStrings);
318void SPIRVAsmPrinter::outputOpExtInstImports(
const Module &M) {
319 for (
auto &CU : MAI->ExtInstSetMap) {
320 unsigned Set = CU.first;
321 MCRegister
Reg = CU.second;
326 static_cast<SPIRV::InstructionSet::InstructionSet
>(Set)),
332void SPIRVAsmPrinter::outputOpMemoryModel() {
344void SPIRVAsmPrinter::outputEntryPoints() {
346 DenseSet<MCRegister> InterfaceIDs;
347 for (
const MachineInstr *
MI : MAI->GlobalVarList) {
348 assert(
MI->getOpcode() == SPIRV::OpVariable);
349 auto SC =
static_cast<SPIRV::StorageClass::StorageClass
>(
356 SC == SPIRV::StorageClass::Input || SC == SPIRV::StorageClass::Output) {
357 const MachineFunction *MF =
MI->getMF();
358 MCRegister
Reg = MAI->getRegisterAlias(MF,
MI->getOperand(0).getReg());
364 for (
const MachineInstr *
MI : MAI->getMSInstrs(SPIRV::MB_EntryPoints)) {
365 SPIRVMCInstLower MCInstLowering;
367 MCInstLowering.
lower(
MI, TmpInst, MAI);
368 for (MCRegister
Reg : InterfaceIDs) {
372 outputMCInst(TmpInst);
377void SPIRVAsmPrinter::outputGlobalRequirements() {
379 MAI->Reqs.checkSatisfiable(*ST);
381 for (
const auto &Cap : MAI->Reqs.getMinimalCapabilities()) {
389 for (
const auto &Ext : MAI->Reqs.getExtensions()) {
393 SPIRV::OperandCategory::ExtensionOperand, Ext),
400void SPIRVAsmPrinter::outputExtFuncDecls() {
402 auto I = MAI->getMSInstrs(SPIRV::MB_ExtFuncDecls).begin(),
403 E = MAI->getMSInstrs(SPIRV::MB_ExtFuncDecls).end();
404 for (;
I !=
E; ++
I) {
405 outputInstruction(*
I);
406 if ((
I + 1) ==
E || (*(
I + 1))->
getOpcode() == SPIRV::OpFunction)
407 outputOpFunctionEnd();
417 if (Ty->isDoubleTy())
420 switch (IntTy->getIntegerBitWidth()) {
434 Type *EleTy = VecTy->getElementType();
435 unsigned Size = VecTy->getNumElements();
457void SPIRVAsmPrinter::outputExecutionModeFromMDNode(
458 MCRegister
Reg, MDNode *Node, SPIRV::ExecutionMode::ExecutionMode EM,
459 unsigned ExpectMDOps, int64_t DefVal) {
467 unsigned NodeSz =
Node->getNumOperands();
468 if (ExpectMDOps > 0 && NodeSz < ExpectMDOps)
469 for (
unsigned i = NodeSz; i < ExpectMDOps; ++i)
474void SPIRVAsmPrinter::outputExecutionModeFromNumthreadsAttribute(
476 SPIRV::ExecutionMode::ExecutionMode EM) {
477 assert(Attr.
isValid() &&
"Function called with an invalid attribute.");
486 assert(NumThreads.size() == 3 &&
"invalid numthreads");
487 for (uint32_t i = 0; i < 3; ++i) {
489 [[maybe_unused]]
bool Result = NumThreads[i].getAsInteger(10, V);
490 assert(!Result &&
"Failed to parse numthreads");
497void SPIRVAsmPrinter::outputExecutionMode(
const Module &M) {
498 NamedMDNode *
Node =
M.getNamedMetadata(
"spirv.ExecutionMode");
500 for (
unsigned i = 0; i <
Node->getNumOperands(); i++) {
507 for (
auto FI =
M.begin(),
E =
M.end(); FI !=
E; ++FI) {
513 MCRegister FReg = MAI->getFuncReg(&
F);
526 static_cast<unsigned>(SPIRV::ExecutionMode::OriginUpperLeft);
531 if (MDNode *Node =
F.getMetadata(
"reqd_work_group_size"))
532 outputExecutionModeFromMDNode(FReg, Node, SPIRV::ExecutionMode::LocalSize,
535 outputExecutionModeFromNumthreadsAttribute(
536 FReg, Attr, SPIRV::ExecutionMode::LocalSize);
537 if (MDNode *Node =
F.getMetadata(
"work_group_size_hint"))
538 outputExecutionModeFromMDNode(FReg, Node,
539 SPIRV::ExecutionMode::LocalSizeHint, 3, 1);
540 if (MDNode *Node =
F.getMetadata(
"intel_reqd_sub_group_size"))
541 outputExecutionModeFromMDNode(FReg, Node,
542 SPIRV::ExecutionMode::SubgroupSize, 0, 0);
543 if (MDNode *Node =
F.getMetadata(
"vec_type_hint")) {
547 unsigned EM =
static_cast<unsigned>(SPIRV::ExecutionMode::VecTypeHint);
553 if (ST->
isKernel() && !
M.getNamedMetadata(
"spirv.ExecutionMode") &&
554 !
M.getNamedMetadata(
"opencl.enable.FP_CONTRACT")) {
558 unsigned EM =
static_cast<unsigned>(SPIRV::ExecutionMode::ContractionOff);
565void SPIRVAsmPrinter::outputAnnotations(
const Module &M) {
566 outputModuleSection(SPIRV::MB_Annotations);
568 for (
auto F =
M.global_begin(),
E =
M.global_end();
F !=
E; ++
F) {
569 if ((*F).getName() !=
"llvm.global.annotations")
571 const GlobalVariable *
V = &(*F);
581 MCRegister
Reg = MAI->getFuncReg(Func);
584 raw_string_ostream OS(DiagMsg);
585 AnnotatedVar->
print(OS);
586 DiagMsg =
"Unknown function in llvm.global.annotations: " + DiagMsg;
594 StringRef AnnotationString;
595 [[maybe_unused]]
bool Success =
601 unsigned Dec =
static_cast<unsigned>(SPIRV::Decoration::UserSemantic);
609void SPIRVAsmPrinter::outputModuleSections() {
610 const Module *
M = MMI->getModule();
612 ST =
static_cast<const SPIRVTargetMachine &
>(
TM).getSubtargetImpl();
615 assert(ST &&
TII && MAI && M &&
"Module analysis is required");
618 outputGlobalRequirements();
620 outputOpExtInstImports(*M);
622 outputOpMemoryModel();
626 outputExecutionMode(*M);
629 outputDebugSourceAndStrings(*M);
631 outputModuleSection(SPIRV::MB_DebugNames);
633 outputModuleSection(SPIRV::MB_DebugModuleProcessed);
636 outputModuleSection(SPIRV::MB_AliasingInsts);
638 outputAnnotations(*M);
643 outputModuleSection(SPIRV::MB_TypeConstVars);
645 outputModuleSection(SPIRV::MB_NonSemanticGlobalDI);
647 outputExtFuncDecls();
652bool SPIRVAsmPrinter::doInitialization(
Module &M) {
653 ModuleSectionsEmitted =
false;
658char SPIRVAsmPrinter::ID = 0;
665LLVMInitializeSPIRVAsmPrinter() {
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_EXTERNAL_VISIBILITY
This file defines the DenseMap class.
const HexagonInstrInfo * TII
Machine Check Debug Module
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
static void addOpsFromMDNode(MDNode *MDN, MCInst &Inst, SPIRV::ModuleAnalysisInfo *MAI)
static bool isFuncOrHeaderInstr(const MachineInstr *MI, const SPIRVInstrInfo *TII)
static unsigned encodeVecTypeHint(Type *Ty)
#define SPIRV_BACKEND_SERVICE_FUN_NAME
static bool printOperand(raw_ostream &OS, const SelectionDAG *G, const SDValue Value)
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static TableGen::Emitter::OptClass< SkeletonEmitter > X("gen-skeleton-class", "Generate example skeleton class")
static std::optional< unsigned > getOpcode(ArrayRef< VPValue * > Values)
Returns the opcode of Values or ~0 if they do not all agree.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
This class is intended to be used as a driving class for all asm writers.
bool doInitialization(Module &M) override
Set up the AsmPrinter when we are working on a new module.
void getAnalysisUsage(AnalysisUsage &AU) const override
Record analysis usage.
Functions, function parameters, and return types can have attributes to indicate how they should be t...
LLVM_ABI StringRef getValueAsString() const
Return the attribute's value as a string.
bool isValid() const
Return true if the attribute is any kind of attribute.
This is the shared class of boolean and integer constants.
This is an important base class in LLVM.
Class to represent fixed width SIMD vectors.
static StringRef dropLLVMManglingEscape(StringRef Name)
If the given string begins with the GlobalValue name mangling escape character '\1',...
Class to represent integer types.
Instances of this class represent a single low-level machine instruction.
void addOperand(const MCOperand Op)
void setOpcode(unsigned Op)
static MCOperand createReg(MCRegister Reg)
static MCOperand createImm(int64_t Val)
Wrapper class representing physical registers. Should be passed by value.
constexpr bool isValid() const
StringRef getName() const
getName - Get the symbol name.
ArrayRef< MDOperand > operands() const
Tracking metadata reference owned by Metadata.
LLVM_ABI MCSymbol * getSymbol() const
Return the MCSymbol for this basic block.
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
Representation of each machine instruction.
const GlobalValue * getGlobal() const
MachineBasicBlock * getMBB() const
const BlockAddress * getBlockAddress() const
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
const char * getSymbolName() const
Register getReg() const
getReg - Returns the register number.
const ConstantFP * getFPImm() const
@ MO_Immediate
Immediate operand.
@ MO_ConstantPoolIndex
Address of indexed Constant in Constant Pool.
@ MO_GlobalAddress
Address of a global value.
@ MO_BlockAddress
Address of a basic block.
@ MO_MachineBasicBlock
MachineBasicBlock reference.
@ MO_Register
Register operand.
@ MO_ExternalSymbol
Name of external global symbol.
@ MO_JumpTableIndex
Address of indexed Jump Table for switch.
@ MO_FPImmediate
Floating-point immediate operand.
A Module instance is used to store all the information related to an LLVM module.
constexpr bool isValid() const
static const char * getRegisterName(MCRegister Reg)
void lower(const MachineInstr *MI, MCInst &OutMI, SPIRV::ModuleAnalysisInfo *MAI) const
const SPIRVInstrInfo * getInstrInfo() const override
bool isAtLeastSPIRVVer(VersionTuple VerToCompareTo) const
VersionTuple getSPIRVVersion() const
unsigned getBound() const
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
StringRef - Represent a constant reference to a string, i.e.
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Primary interface to the complete machine description for the target machine.
The instances of the Type class are immutable: once they are created, they are never changed.
Value * getOperand(unsigned i) const
LLVM_ABI void print(raw_ostream &O, bool IsForDebug=false) const
Implement operator<< on Value.
LLVM_ABI const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
unsigned getMajor() const
Retrieve the major version number.
std::optional< unsigned > getMinor() const
Retrieve the minor version number, if provided.
std::pair< iterator, bool > insert(const ValueT &V)
This class implements an extremely fast bulk output stream that can only output to a stream.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ C
The default llvm calling convention, compatible with C.
NodeAddr< NodeBase * > Node
NodeAddr< FuncNode * > Func
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
Target & getTheSPIRV32Target()
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI bool getConstantStringInfo(const Value *V, StringRef &Str, bool TrimAtNul=true)
This function computes the length of a null-terminated C string pointed to by V.
std::string getExtInstSetName(SPIRV::InstructionSet::InstructionSet Set)
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
std::string getSymbolicOperandMnemonic(SPIRV::OperandCategory::OperandCategory Category, int32_t Value)
bool isEntryPoint(const Function &F)
Target & getTheSPIRV64Target()
Target & getTheSPIRVLogicalTarget()
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Type * getMDOperandAsType(const MDNode *N, unsigned I)
void addStringImm(const StringRef &Str, MCInst &Inst)
RegisterAsmPrinter - Helper template for registering a target specific assembly printer,...
static struct SPIRV::ModuleAnalysisInfo MAI
MCRegister getFuncReg(const Function *F)