40template <
typename MapT>
41static std::optional<MCRegister> lookupOptReg(
const MapT &Map,
42 typename MapT::key_type
Key) {
46 assert(It->second.isValid() &&
"invalid register stored in map");
73 if (CT->getTag() == dwarf::DW_TAG_array_type) {
89 }
else if (CT->getTag() == dwarf::DW_TAG_structure_type ||
90 CT->getTag() == dwarf::DW_TAG_class_type ||
91 CT->getTag() == dwarf::DW_TAG_union_type) {
97 if (DT && DT->getTag() == dwarf::DW_TAG_pointer_type)
99 else if (DT && DT->getTag() == dwarf::DW_TAG_typedef)
104 NSDIFlagIsProtected = 1u << 0,
105 NSDIFlagIsPrivate = 1u << 1,
106 NSDIFlagIsPublic = NSDIFlagIsPrivate | NSDIFlagIsProtected,
107 NSDIFlagIsLocal = 1u << 2,
108 NSDIFlagIsDefinition = 1u << 3,
109 NSDIFlagFwdDecl = 1u << 4,
110 NSDIFlagArtificial = 1u << 5,
111 NSDIFlagExplicit = 1u << 6,
112 NSDIFlagPrototyped = 1u << 7,
113 NSDIFlagObjectPointer = 1u << 8,
114 NSDIFlagStaticMember = 1u << 9,
115 NSDIFlagIndirectVariable = 1u << 10,
116 NSDIFlagLValueReference = 1u << 11,
117 NSDIFlagRValueReference = 1u << 12,
118 NSDIFlagIsOptimized = 1u << 13,
119 NSDIFlagIsEnumClass = 1u << 14,
120 NSDIFlagTypePassByValue = 1u << 15,
121 NSDIFlagTypePassByReference = 1u << 16,
122 NSDIFlagUnknownPhysicalLayout = 1u << 17,
128 Flags |= NSDIFlagIsPublic;
130 Flags |= NSDIFlagIsProtected;
132 Flags |= NSDIFlagIsPrivate;
133 if (DFlags & DINode::FlagFwdDecl)
134 Flags |= NSDIFlagFwdDecl;
135 if (DFlags & DINode::FlagArtificial)
136 Flags |= NSDIFlagArtificial;
137 if (DFlags & DINode::FlagExplicit)
138 Flags |= NSDIFlagExplicit;
139 if (DFlags & DINode::FlagPrototyped)
140 Flags |= NSDIFlagPrototyped;
141 if (DFlags & DINode::FlagObjectPointer)
142 Flags |= NSDIFlagObjectPointer;
143 if (DFlags & DINode::FlagStaticMember)
144 Flags |= NSDIFlagStaticMember;
145 if (DFlags & DINode::FlagLValueReference)
146 Flags |= NSDIFlagLValueReference;
147 if (DFlags & DINode::FlagRValueReference)
148 Flags |= NSDIFlagRValueReference;
149 if (DFlags & DINode::FlagTypePassByValue)
150 Flags |= NSDIFlagTypePassByValue;
151 if (DFlags & DINode::FlagTypePassByReference)
152 Flags |= NSDIFlagTypePassByReference;
153 if (DFlags & DINode::FlagEnumClass)
154 Flags |= NSDIFlagIsEnumClass;
161 if (GV->isLocalToUnit())
162 Flags |= NSDIFlagIsLocal;
163 if (GV->isDefinition())
164 Flags |= NSDIFlagIsDefinition;
167 if (SP->isLocalToUnit())
168 Flags |= NSDIFlagIsLocal;
169 if (SP->isOptimized())
170 Flags |= NSDIFlagIsOptimized;
171 if (SP->isDefinition())
172 Flags |= NSDIFlagIsDefinition;
173 Flags |= mapDIFlagsToNonSemantic(SP->getFlags());
175 if (DN->
getTag() == dwarf::DW_TAG_reference_type)
176 Flags |= NSDIFlagLValueReference;
177 if (DN->
getTag() == dwarf::DW_TAG_rvalue_reference_type)
178 Flags |= NSDIFlagRValueReference;
180 Flags |= mapDIFlagsToNonSemantic(Ty->getFlags());
182 Flags |= mapDIFlagsToNonSemantic(LV->getFlags());
188static uint32_t mapCompositeTypeTag(
unsigned Tag) {
190 case dwarf::DW_TAG_class_type:
192 case dwarf::DW_TAG_structure_type:
194 case dwarf::DW_TAG_union_type:
198 ". Expecting 0, 1 or 2");
213 bool SeenOpVariable =
false;
215 if (
MI.getOpcode() == SPIRV::OpVariable) {
216 SeenOpVariable =
true;
218 LastOpVariable = &
MI;
222 bool CanInterleaveWithOpVariable =
223 MI.getOpcode() == SPIRV::OpLine ||
MI.getOpcode() == SPIRV::OpNoLine;
224 if (SeenOpVariable && !CanInterleaveWithOpVariable &&
228 return LastOpVariable;
239unsigned SPIRVNonSemanticDebugHandler::toNSDISrcLang(
unsigned DwarfSrcLang) {
240 switch (DwarfSrcLang) {
241 case dwarf::DW_LANG_OpenCL:
243 case dwarf::DW_LANG_OpenCL_CPP:
245 case dwarf::DW_LANG_CPP_for_OpenCL:
247 case dwarf::DW_LANG_GLSL:
249 case dwarf::DW_LANG_HLSL:
251 case dwarf::DW_LANG_SYCL:
253 case dwarf::DW_LANG_Zig:
267 if (!
F.getSubprogram())
287 CompileUnits.clear();
289 PointerTypes.clear();
290 SubroutineTypes.clear();
293 CompositeTypes.clear();
294 TypedefTypes.clear();
295 SubprogramDeclarations.clear();
296 SubprogramDefinitions.clear();
297 UniqueDebugLocations.clear();
298 GlobalVariableDebugInfoMap.clear();
299 DebugFunctionDeclarationRegs.clear();
300 DebugFunctionRegs.clear();
301 ScopeToPathOpStringReg.clear();
302 CUToCompilationUnitDbgReg.clear();
303 DebugSourceRegByFileStr.clear();
304 DebugTypeRegs.clear();
305 OpStringContentCache.clear();
306 I32ConstantCache.clear();
307 DebugTypeFunctionCache.clear();
308 GlobalDIEmitted =
false;
309 GlobalNSDIEnabled =
false;
310 CurrentMAI =
nullptr;
312 NonSemanticOpStringsSectionEmitted =
false;
322 CompileUnitInfo Info;
325 Info.FilePath = File->getFilename();
328 File->getFilename());
331 Info.SpirvSourceLanguage = toNSDISrcLang(
CU->getSourceLanguage().getName());
332 CompileUnits.push_back(std::move(Info));
338 if (
const NamedMDNode *Flags = M->getNamedMetadata(
"llvm.module.flags")) {
339 for (
const auto *
Op : Flags->operands()) {
353 partitionTypes(Ty, BasicTypes, PointerTypes, SubroutineTypes, VectorTypes,
354 ArrayTypes, CompositeTypes, TypedefTypes);
358 if (SP->isDefinition())
359 SubprogramDefinitions.push_back(SP);
361 SubprogramDeclarations.push_back(SP);
368 G.getDebugInfo(GVEs);
379 GlobalVariableDebugInfoMap.try_emplace(
380 GV, GlobalVariableDebugInfo{Expr, DIGVToLLVMGV.
lookup(GV)});
388 if (CompileUnits.empty())
390 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_non_semantic_info))
403void SPIRVNonSemanticDebugHandler::emitMCInst(
MCInst &Inst) {
408SPIRVNonSemanticDebugHandler::emitOpString(
StringRef S,
419MCRegister SPIRVNonSemanticDebugHandler::emitOpStringIfNew(
422 assert(!NonSemanticOpStringsSectionEmitted &&
423 "emitOpStringIfNew is only valid while emitting SPIR-V section 7");
425 auto [It,
Inserted] = OpStringContentCache.try_emplace(S, MCRegister());
427 It->second = emitOpString(S, MAI);
434 assert(NonSemanticOpStringsSectionEmitted &&
435 "getCachedOpStringReg requires emitNonSemanticDebugStrings() first");
437 auto It = OpStringContentCache.find(S);
438 assert(It != OpStringContentCache.end() &&
439 "NSDI OpString missing from cache; emitNonSemanticDebugStrings must "
440 "cache every string used in section 10");
444MCRegister SPIRVNonSemanticDebugHandler::emitAndCacheScopePathOpStringReg(
446 auto [It,
Inserted] = ScopeToPathOpStringReg.try_emplace(Scope, MCRegister());
448 It->second = emitOpStringIfNew(getDebugFullPath(Scope), MAI);
452MCRegister SPIRVNonSemanticDebugHandler::getCachedScopePathOpStringReg(
453 const DIScope *Scope,
bool UseEmptyPathIfNullScope) {
455 assert(UseEmptyPathIfNullScope &&
456 "null scope path lookup requires UseEmptyPathIfNullScope");
457 assert(CachedEmptyStringReg.isValid() &&
458 "empty path OpString must be cached in emitNonSemanticDebugStrings");
459 return CachedEmptyStringReg;
461 auto It = ScopeToPathOpStringReg.find(Scope);
462 assert(It != ScopeToPathOpStringReg.end() &&
463 "path OpString must be cached in emitNonSemanticDebugStrings");
464 MCRegister FileStrReg = It->second;
465 assert(FileStrReg.
isValid() &&
"path OpString id must be valid once cached");
469MCRegister SPIRVNonSemanticDebugHandler::emitOpConstantI32(
486MCRegister SPIRVNonSemanticDebugHandler::emitExtInst(
487 SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
503MCRegister SPIRVNonSemanticDebugHandler::getOrEmitDebugTypeFunction(
511 MCRegister
Reg = emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeFunction,
512 VoidTypeReg, ExtInstSetReg,
Ops, MAI);
517MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeVoidReg(
519 if (!CachedOpTypeVoidReg.isValid())
520 CachedOpTypeVoidReg = findOrEmitOpTypeVoid(MAI);
521 return CachedOpTypeVoidReg;
524MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeInt32Reg(
526 if (!CachedOpTypeInt32Reg.isValid())
527 CachedOpTypeInt32Reg = findOrEmitOpTypeInt32(MAI);
528 return CachedOpTypeInt32Reg;
531MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeVoid(
534 if (
MI->getOpcode() == SPIRV::OpTypeVoid)
545MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeInt32(
548 if (
MI->getOpcode() == SPIRV::OpTypeInt &&
549 MI->getOperand(1).getImm() == 32 &&
MI->getOperand(2).getImm() == 0)
562std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypePointer(
567 if (!PT->getDWARFAddressSpace().has_value())
570 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
571 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
572 MCRegister DebugTypePointerFlagsReg =
573 emitOpConstantI32(transDebugFlags(PT), I32TypeReg, MAI);
577 const auto &
ST =
static_cast<const SPIRVSubtarget &
>(
Asm->getSubtargetInfo());
578 MCRegister StorageClassReg = emitOpConstantI32(
582 if (
const DIType *BaseTy = PT->getBaseType()) {
583 auto BaseIt = DebugTypeRegs.find(BaseTy);
584 if (BaseIt != DebugTypeRegs.end())
586 SPIRV::NonSemanticExtInst::DebugTypePointer, VoidTypeReg,
588 {BaseIt->second, StorageClassReg, DebugTypePointerFlagsReg}, MAI);
597 SPIRV::NonSemanticExtInst::DebugTypePointer, VoidTypeReg, ExtInstSetReg,
598 {CachedDebugInfoNoneReg, StorageClassReg, DebugTypePointerFlagsReg}, MAI);
601std::optional<MCRegister>
602SPIRVNonSemanticDebugHandler::emitDebugTypeFunctionForSubroutineType(
605 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
606 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
607 MCRegister DebugTypeFunctionFlagsReg =
608 emitOpConstantI32(transDebugFlags(ST), I32TypeReg, MAI);
609 DITypeArray
TA =
ST->getTypeArray();
611 Ops.push_back(DebugTypeFunctionFlagsReg);
616 Ops.push_back(VoidTypeReg);
618 for (
unsigned I = 0,
E =
TA.size();
I !=
E; ++
I) {
619 bool IsReturnType = (
I == 0);
620 auto OptReg = mapDISignatureTypeToReg(TA[
I], VoidTypeReg, IsReturnType);
625 Ops.push_back(*OptReg);
628 return getOrEmitDebugTypeFunction(
Ops, VoidTypeReg, ExtInstSetReg, MAI);
632std::optional<MCRegister>
633SPIRVNonSemanticDebugHandler::resolveDebugFunctionParent(
635 const DIScope *
Scope =
SP->getScope();
642 return lookupOptReg(DebugTypeRegs, Ty);
645 const DICompileUnit *ParentCU =
SP->getUnit();
646 if (!ParentCU && !CompileUnits.empty())
647 ParentCU = CompileUnits[0].TheCU;
650 return lookupOptReg(CUToCompilationUnitDbgReg, ParentCU);
653std::optional<MCRegister> SPIRVNonSemanticDebugHandler::resolveTypeScopeParent(
658 return lookupOptReg(DebugTypeRegs, Ty);
662 if (CompileUnits.empty())
665 return lookupOptReg(CUToCompilationUnitDbgReg, CompileUnits[0].TheCU);
668std::optional<MCRegister>
669SPIRVNonSemanticDebugHandler::emitDebugFunctionDeclaration(
672 assert(SP &&
"SP must not be null in emitDebugFunctionDeclaration");
674 "SP must not be a definition in emitDebugFunctionDeclaration");
677 const DISubroutineType *
ST =
SP->getType();
679 auto FnTyRegOpt = lookupOptReg(DebugTypeRegs, ST);
682 MCRegister FnTyReg = *FnTyRegOpt;
684 auto ParentRegOpt = resolveDebugFunctionParent(SP);
688 MCRegister ParentReg = *ParentRegOpt;
690 MCRegister FileStrReg = getCachedScopePathOpStringReg(SP);
692 MCRegister NameReg = getCachedOpStringReg(
SP->getName());
693 MCRegister LinkageReg = getCachedOpStringReg(
SP->getLinkageName());
694 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
698 emitOpConstantI32(
static_cast<uint32_t
>(
SP->getLine()), I32TypeReg, MAI);
699 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
701 uint32_t FlagsVal = transDebugFlags(SP);
704 FlagsVal &= ~NSDIFlagIsDefinition;
705 MCRegister FlagsReg = emitOpConstantI32(FlagsVal, I32TypeReg, MAI);
707 return emitExtInst(SPIRV::NonSemanticExtInst::DebugFunctionDeclaration,
708 VoidTypeReg, ExtInstSetReg,
709 {NameReg, FnTyReg, SrcReg, LineReg, ColReg, ParentReg,
710 LinkageReg, FlagsReg},
714std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugFunction(
717 assert(SP &&
"SP must not be null in emitDebugFunction");
718 assert(
SP->isDefinition() &&
"SP must be a definition in emitDebugFunction");
720 const DISubroutineType *
ST =
SP->getType();
721 auto FnTyRegOpt = lookupOptReg(DebugTypeRegs, ST);
725 auto ParentRegOpt = resolveDebugFunctionParent(SP);
729 MCRegister NameReg = getCachedOpStringReg(
SP->getName());
730 MCRegister LinkageReg = getCachedOpStringReg(
SP->getLinkageName());
731 MCRegister FileStrReg = getCachedScopePathOpStringReg(SP);
732 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
736 emitOpConstantI32(
static_cast<uint32_t
>(
SP->getLine()), I32TypeReg, MAI);
739 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
740 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(SP), I32TypeReg, MAI);
741 MCRegister ScopeLineReg = emitOpConstantI32(
742 static_cast<uint32_t
>(
SP->getScopeLine()), I32TypeReg, MAI);
745 LineReg, ColReg, *ParentRegOpt,
746 LinkageReg, FlagsReg, ScopeLineReg};
748 if (
const DISubprogram *Decl =
SP->getDeclaration()) {
749 if (
auto DeclRegOpt = lookupOptReg(DebugFunctionDeclarationRegs, Decl))
750 Ops.push_back(*DeclRegOpt);
753 return emitExtInst(SPIRV::NonSemanticExtInst::DebugFunction, VoidTypeReg,
754 ExtInstSetReg,
Ops, MAI);
757std::optional<MCRegister> SPIRVNonSemanticDebugHandler::mapDISignatureTypeToReg(
762 assert(CachedDebugInfoNoneReg.isValid() &&
763 "DebugInfoNone must be emitted before DISubroutineType operands");
764 return CachedDebugInfoNoneReg;
766 return lookupOptReg(DebugTypeRegs, Ty);
769MCRegister SPIRVNonSemanticDebugHandler::resolveGlobalVariableParent(
776 assert(!CompileUnits.empty() &&
777 "resolveGlobalVariableParent requires non-empty CompileUnits");
778 std::optional<MCRegister> ParentRegOpt =
779 lookupOptReg(CUToCompilationUnitDbgReg, CompileUnits[0].TheCU);
780 assert(ParentRegOpt &&
"DebugCompilationUnit must be emitted before "
781 "resolveGlobalVariableParent");
783 return *ParentRegOpt;
787std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugExpression(
792std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugGlobalVariable(
796 assert(GV &&
"GV must not be null in emitDebugGlobalVariable");
798 MCRegister ParentReg = resolveGlobalVariableParent(GV);
804 MCRegister TyReg = CachedDebugInfoNoneReg;
805 if (
const DIType *Ty = GV->
getType()) {
806 auto TyRegOpt = lookupOptReg(DebugTypeRegs, Ty);
812 std::optional<MCRegister> StaticMemberRegOpt;
814 StaticMemberRegOpt = lookupOptReg(DebugTypeRegs, SM);
815 if (!StaticMemberRegOpt)
819 MCRegister NameReg = getCachedOpStringReg(GV->
getName());
820 MCRegister LinkageReg = getCachedOpStringReg(GV->
getLinkageName());
821 MCRegister FileStrReg = getCachedScopePathOpStringReg(
823 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
827 emitOpConstantI32(
static_cast<uint32_t
>(GV->
getLine()), I32TypeReg, MAI);
831 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
835 MCRegister VariableReg = CachedDebugInfoNoneReg;
836 if (
const GlobalVariable *LLVMGV =
Info.LLVMGV) {
840 }
else if (
Info.Expr) {
842 emitDebugExpression(
Info.Expr, VoidTypeReg, ExtInstSetReg, MAI))
843 VariableReg = *ExprReg;
846 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(GV), I32TypeReg, MAI);
849 LineReg, ColReg, ParentReg,
850 LinkageReg, VariableReg, FlagsReg};
852 if (StaticMemberRegOpt)
853 Ops.push_back(*StaticMemberRegOpt);
855 return emitExtInst(SPIRV::NonSemanticExtInst::DebugGlobalVariable,
856 VoidTypeReg, ExtInstSetReg,
Ops, MAI);
859std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeVector(
865 auto BTIt = DebugTypeRegs.find(BaseTy);
866 if (BTIt == DebugTypeRegs.end())
879 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
880 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
881 MCRegister CountReg = emitOpConstantI32(
882 static_cast<uint32_t
>(CI->getZExtValue()), I32TypeReg, MAI);
883 return emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeVector, VoidTypeReg,
884 ExtInstSetReg, {BTIt->second, CountReg}, MAI);
887std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeArray(
892 auto BaseRegOpt = lookupOptReg(DebugTypeRegs, AT->
getBaseType());
896 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
897 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
900 Ops.push_back(*BaseRegOpt);
916 const APInt &
Value = CI->getValue();
917 if (
Value.getActiveBits() <= 32)
918 Count =
static_cast<uint32_t
>(
Value.getZExtValue());
920 Ops.push_back(emitOpConstantI32(
Count, I32TypeReg, MAI));
923 return emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeArray, VoidTypeReg,
924 ExtInstSetReg,
Ops, MAI);
927std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeMember(
931 auto TyRegOpt = lookupOptReg(DebugTypeRegs,
M->getBaseType());
935 MCRegister NameReg = getCachedOpStringReg(
M->getName());
936 MCRegister FileStrReg = getCachedScopePathOpStringReg(
938 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
941 emitOpConstantI32(
static_cast<uint32_t
>(
M->getLine()), I32TypeReg, MAI);
944 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
945 MCRegister OffsetReg = emitOpConstantI32(
946 static_cast<uint32_t
>(
M->getOffsetInBits()), I32TypeReg, MAI);
947 MCRegister SizeReg = emitOpConstantI32(
948 static_cast<uint32_t
>(
M->getSizeInBits()), I32TypeReg, MAI);
949 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(M), I32TypeReg, MAI);
960 return emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeMember, VoidTypeReg,
962 {NameReg, *TyRegOpt, SrcReg, LineReg, ColReg, OffsetReg,
967std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeComposite(
971 auto ParentRegOpt = resolveTypeScopeParent(CT->
getScope());
975 MCRegister NameReg = getCachedOpStringReg(CT->
getName());
976 MCRegister LinkageReg = getCachedOpStringReg(CT->
getIdentifier());
977 MCRegister FileStrReg = getCachedScopePathOpStringReg(
979 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
983 emitOpConstantI32(mapCompositeTypeTag(CT->
getTag()), I32TypeReg, MAI);
985 emitOpConstantI32(
static_cast<uint32_t
>(CT->
getLine()), I32TypeReg, MAI);
986 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
989 MCRegister SizeReg = CachedDebugInfoNoneReg;
991 SizeReg = emitOpConstantI32(
static_cast<uint32_t
>(CT->
getSizeInBits()),
994 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(CT), I32TypeReg, MAI);
997 LineReg, ColReg, *ParentRegOpt,
998 LinkageReg, SizeReg, FlagsReg};
1000 return emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeComposite, VoidTypeReg,
1001 ExtInstSetReg,
Ops, MAI);
1004std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypedef(
1008 auto BaseRegOpt = lookupOptReg(DebugTypeRegs, TD->getBaseType());
1010 return std::nullopt;
1012 MCRegister NameReg = getCachedOpStringReg(TD->
getName());
1013 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1015 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1016 ExtInstSetReg, MAI);
1017 MCRegister LineReg =
1018 emitOpConstantI32(
static_cast<uint32_t
>(TD->
getLine()), I32TypeReg, MAI);
1020 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
1028 MCRegister ParentReg;
1030 if (
auto TyRegOpt = lookupOptReg(DebugTypeRegs, Ty))
1031 ParentReg = *TyRegOpt;
1033 assert(!CompileUnits.empty() &&
1034 "emitDebugTypedef requires a compile unit for the Parent operand");
1036 lookupOptReg(CUToCompilationUnitDbgReg, CompileUnits[0].TheCU);
1037 assert(CURegOpt &&
"DebugCompilationUnit must be emitted before typedefs");
1038 ParentReg = *CURegOpt;
1042 SPIRV::NonSemanticExtInst::DebugTypedef, VoidTypeReg, ExtInstSetReg,
1043 {NameReg, *BaseRegOpt, SrcReg, LineReg, ColReg, ParentReg}, MAI);
1048 if (CompileUnits.empty())
1056 for (
const CompileUnitInfo &Info : CompileUnits) {
1058 MCRegister PathReg = emitOpStringIfNew(Info.FilePath, MAI);
1059 ScopeToPathOpStringReg[Info.TheCU] = PathReg;
1060 if (
const DIFile *
F = Info.TheCU->getFile())
1061 ScopeToPathOpStringReg[
F] = PathReg;
1066 emitOpStringIfNew(
BT->getName(), MAI);
1069 SubprogramDeclarations, SubprogramDefinitions)) {
1070 emitOpStringIfNew(SP->getName(), MAI);
1071 emitOpStringIfNew(SP->getLinkageName(), MAI);
1072 emitAndCacheScopePathOpStringReg(SP, MAI);
1079 emitOpStringIfNew(CT->
getName(), MAI);
1081 emitAndCacheScopePathOpStringReg(CT->
getFile(), MAI);
1084 if (!M || M->getTag() != dwarf::DW_TAG_member)
1086 emitOpStringIfNew(M->getName(), MAI);
1087 emitAndCacheScopePathOpStringReg(M->getFile(), MAI);
1093 emitOpStringIfNew(TD->
getName(), MAI);
1094 emitAndCacheScopePathOpStringReg(TD->
getFile(), MAI);
1097 for (
const auto &[GV,
_] : GlobalVariableDebugInfoMap) {
1098 emitOpStringIfNew(GV->
getName(), MAI);
1100 emitAndCacheScopePathOpStringReg(GV->
getFile(), MAI);
1104 emitAndCacheScopePathOpStringReg(
DL->getScope(), MAI);
1106 CachedEmptyStringReg = emitOpStringIfNew(
"", MAI);
1109 NonSemanticOpStringsSectionEmitted =
true;
1113void SPIRVNonSemanticDebugHandler::emitDebugFunctionDefinition(
1117 "DebugFunctionDefinition operands must be valid");
1118 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
1120 emitExtInst(SPIRV::NonSemanticExtInst::DebugFunctionDefinition, VoidTypeReg,
1121 ExtInstSetReg, {DebugFunctionReg, OpFunctionReg}, MAI);
1124void SPIRVNonSemanticDebugHandler::resetPerFunctionDebugState() {
1125 CurrentMF =
nullptr;
1126 LastFunctionOpVariable =
nullptr;
1127 DebugFunctionDefinitionEmitted =
false;
1128 LastLineMI =
nullptr;
1131void SPIRVNonSemanticDebugHandler::preparePerFunctionDebug(
1133 resetPerFunctionDebugState();
1134 if (!GlobalNSDIEnabled || !CurrentMAI)
1145 if (!SP || !
SP->isDefinition())
1150 LastFunctionOpVariable =
1151 findLastFunctionOpVariableDeclaration(*MF, *CurrentMAI);
1154void SPIRVNonSemanticDebugHandler::tryEmitDebugFunctionDefinition(
1156 if (DebugFunctionDefinitionEmitted || !GlobalNSDIEnabled)
1159 assert(CurrentMF &&
"no current MachineFunction");
1160 const Function &
F = CurrentMF->getFunction();
1161 const DISubprogram *
SP =
F.getSubprogram();
1162 if (!SP || !
SP->isDefinition())
1165 auto DFIt = DebugFunctionRegs.find(SP);
1166 if (DFIt == DebugFunctionRegs.end())
1173 emitDebugFunctionDefinition(DFIt->second, OpFunctionReg, MAI);
1174 DebugFunctionDefinitionEmitted =
true;
1179 preparePerFunctionDebug(MF);
1184 resetPerFunctionDebugState();
1191 if (!DebugFunctionDefinitionEmitted)
1193 emitDebugLineForInstruction(
MI);
1197 return Opcode == SPIRV::OpSelectionMerge || Opcode == SPIRV::OpLoopMerge ||
1198 Opcode == SPIRV::OpLoopControlINTEL;
1205 switch (
MI->getOpcode()) {
1206 case SPIRV::OpFunction:
1207 case SPIRV::OpFunctionParameter:
1208 case SPIRV::OpFunctionEnd:
1209 case SPIRV::OpLabel:
1221 :
MI->getPrevNode();
1222 Adj; Adj = Forward ? Adj->getNextNode() : Adj->getPrevNode()) {
1230void SPIRVNonSemanticDebugHandler::emitDebugLineForInstruction(
1232 assert(DebugFunctionDefinitionEmitted &&
1233 "DebugFunctionDefinition must be emitted");
1234 assert(CurrentMAI &&
"CurrentMAI must be set");
1236 SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI;
1254 assert(
MI &&
"Merge instruction must be followed by a terminator");
1258 if (LastLineMI &&
MI->getParent() != LastLineMI->getParent())
1259 LastLineMI =
nullptr;
1261 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
1264 const DILocation *
DL =
MI->getDebugLoc().get();
1269 emitExtInst(SPIRV::NonSemanticExtInst::DebugNoLine, VoidTypeReg,
1270 ExtInstSetReg, {}, MAI);
1271 LastLineMI =
nullptr;
1281 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1282 DL->getScope(),
true);
1283 unsigned Line =
DL->getLine();
1284 unsigned Col =
DL->getColumn();
1286 MCRegister SrcReg = DebugSourceRegByFileStr.lookup(FileStrReg.
id());
1287 MCRegister LineReg = I32ConstantCache.lookup(Line);
1288 MCRegister ColStartReg = I32ConstantCache.lookup(Col);
1289 MCRegister ColEndReg = I32ConstantCache.lookup(Col + 1);
1301 if (LastLineMI &&
MI->getDebugLoc() == LastLineMI->getDebugLoc())
1305 emitExtInst(SPIRV::NonSemanticExtInst::DebugLine, VoidTypeReg, ExtInstSetReg,
1306 {SrcReg, LineReg, LineReg, ColStartReg, ColEndReg}, MAI);
1315 if (!
MI || !GlobalNSDIEnabled || DebugFunctionDefinitionEmitted || !CurrentMF)
1318 if (
MI != LastFunctionOpVariable)
1324 assert(CurrentMAI &&
"CurrentMAI must be set");
1325 tryEmitDebugFunctionDefinition(*CurrentMAI);
1330 if (!GlobalNSDIEnabled || DebugFunctionDefinitionEmitted || !CurrentMF)
1333 assert(CurrentMF == &MF &&
1334 "notification does not match the current MachineFunction");
1336 if (LastFunctionOpVariable)
1342 tryEmitDebugFunctionDefinition(*CurrentMAI);
1347 if (GlobalDIEmitted)
1350 GlobalDIEmitted =
true;
1352 if (CompileUnits.empty()) {
1353 GlobalNSDIEnabled =
false;
1359 if (!ExtInstSetReg.
isValid()) {
1360 GlobalNSDIEnabled =
false;
1365 assert(NonSemanticOpStringsSectionEmitted &&
1366 "emitNonSemanticDebugStrings() must run before "
1367 "emitNonSemanticGlobalDebugInfo()");
1372 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
1373 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
1375 CachedDebugInfoNoneReg = emitExtInst(SPIRV::NonSemanticExtInst::DebugInfoNone,
1376 VoidTypeReg, ExtInstSetReg, {}, MAI);
1388 MCRegister DebugInfoVersionReg = emitOpConstantI32(100, I32TypeReg, MAI);
1390 emitOpConstantI32(
static_cast<uint32_t>(DwarfVersion), I32TypeReg, MAI);
1395 map_to_vector(CompileUnits, [&](
const CompileUnitInfo &Info) {
1396 return emitOpConstantI32(Info.SpirvSourceLanguage, I32TypeReg, MAI);
1400 for (
auto [Info, SrcLangReg] :
llvm::zip(CompileUnits, SrcLangRegs)) {
1401 MCRegister FileStrReg = ScopeToPathOpStringReg.lookup(Info.TheCU);
1403 "CU path OpString must be emitted in emitNonSemanticDebugStrings");
1404 MCRegister DebugSourceReg = getOrEmitDebugSourceForFileStrReg(
1405 FileStrReg, VoidTypeReg, ExtInstSetReg, MAI);
1407 SPIRV::NonSemanticExtInst::DebugCompilationUnit, VoidTypeReg,
1409 {DebugInfoVersionReg, DwarfVersionReg, DebugSourceReg, SrcLangReg},
1412 CUToCompilationUnitDbgReg[Info.TheCU] = CUDbgReg;
1417 MCRegister I32ZeroReg = emitOpConstantI32(0, I32TypeReg, MAI);
1419 DebugTypeRegs.clear();
1422 MCRegister NameReg = getCachedOpStringReg(
BT->getName());
1424 static_cast<uint32_t>(
BT->getSizeInBits()), I32TypeReg, MAI);
1428 unsigned Encoding = 0;
1429 switch (
BT->getEncoding()) {
1430 case dwarf::DW_ATE_address:
1433 case dwarf::DW_ATE_boolean:
1436 case dwarf::DW_ATE_float:
1439 case dwarf::DW_ATE_signed:
1442 case dwarf::DW_ATE_signed_char:
1445 case dwarf::DW_ATE_unsigned:
1448 case dwarf::DW_ATE_unsigned_char:
1452 MCRegister EncodingReg = emitOpConstantI32(Encoding, I32TypeReg, MAI);
1455 SPIRV::NonSemanticExtInst::DebugTypeBasic, VoidTypeReg, ExtInstSetReg,
1456 {NameReg, SizeReg, EncodingReg, I32ZeroReg}, MAI);
1457 DebugTypeRegs[
BT] = BTReg;
1462 if (
auto VecReg = emitDebugTypeVector(VT, ExtInstSetReg, MAI))
1463 DebugTypeRegs[VT] = *VecReg;
1468 if (
auto PtrReg = emitDebugTypePointer(PT, ExtInstSetReg, MAI))
1469 DebugTypeRegs[PT] = *PtrReg;
1476 if (
auto ArrReg = emitDebugTypeArray(AT, ExtInstSetReg, MAI))
1477 DebugTypeRegs[AT] = *ArrReg;
1483 emitDebugTypeFunctionForSubroutineType(ST, ExtInstSetReg, MAI))
1484 DebugTypeRegs[ST] = *FnTyReg;
1494 emitDebugTypedef(TD, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI))
1495 DebugTypeRegs[TD] = *TDReg;
1499 for (
const DISubprogram *SP : SubprogramDeclarations) {
1500 if (
auto DeclReg = emitDebugFunctionDeclaration(SP, VoidTypeReg, I32TypeReg,
1501 ExtInstSetReg, MAI))
1502 DebugFunctionDeclarationRegs[SP] = *DeclReg;
1513 if (!M || M->getTag() != dwarf::DW_TAG_member)
1515 if (
auto MemberReg = emitDebugTypeMember(M, VoidTypeReg, I32TypeReg,
1516 ExtInstSetReg, MAI))
1519 if (
auto CompReg = emitDebugTypeComposite(CT, MemberRegs, VoidTypeReg,
1520 I32TypeReg, ExtInstSetReg, MAI))
1521 DebugTypeRegs[CT] = *CompReg;
1527 emitDebugFunction(SP, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI))
1528 DebugFunctionRegs[SP] = *FnReg;
1532 for (
const auto &[GV, Info] : GlobalVariableDebugInfoMap)
1533 emitDebugGlobalVariable(GV, Info, VoidTypeReg, I32TypeReg, ExtInstSetReg,
1537 emitOpConstantI32(
DL->getLine(), I32TypeReg, MAI);
1538 emitOpConstantI32(
DL->getColumn(), I32TypeReg, MAI);
1539 emitOpConstantI32(
DL->getColumn() + 1, I32TypeReg, MAI);
1541 getCachedScopePathOpStringReg(
DL->getScope(),
1543 getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg, ExtInstSetReg,
1547 GlobalNSDIEnabled =
true;
1551SPIRVNonSemanticDebugHandler::getDebugFullPath(
const DIScope *Scope)
const {
1567MCRegister SPIRVNonSemanticDebugHandler::getOrEmitDebugSourceForFileStrReg(
1570 const unsigned Key = FileStrReg.
id();
1571 auto It = DebugSourceRegByFileStr.find(
Key);
1572 if (It != DebugSourceRegByFileStr.end())
1575 MCRegister
DS = emitExtInst(SPIRV::NonSemanticExtInst::DebugSource,
1576 VoidTypeReg, ExtInstSetReg, {FileStrReg}, MAI);
1577 DebugSourceRegByFileStr[
Key] =
DS;
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains constants used for implementing Dwarf debug support.
Module.h This file contains the declarations for the Module class.
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
static constexpr StringLiteral Filename
static const MachineInstr * findAdjacentEmittedInstruction(const MachineInstr *MI, SPIRV::ModuleAnalysisInfo &MAI, bool Forward)
static bool isMergeInstruction(unsigned Opcode)
static bool isDebugLineTarget(const MachineInstr *MI, SPIRV::ModuleAnalysisInfo &MAI)
static void collectUniqueDebugLocations(const Module &M, SetVector< const DILocation * > &Out)
#define SPIRV_BACKEND_SERVICE_FUN_NAME
This file implements a set that has insertion order iteration characteristics.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
This class is intended to be used as a driving class for all asm writers.
std::unique_ptr< MCStreamer > OutStreamer
This is the MCStreamer object for the file we are generating.
const MCSubtargetInfo & getSubtargetInfo() const
Return information about subtarget.
bool isValid() const
Return true if the attribute is any kind of attribute.
Basic type, like 'int' or 'float'.
StringRef getIdentifier() const
DINodeArray getElements() const
DIType * getBaseType() const
A pair of DIGlobalVariable and DIExpression.
DIDerivedType * getStaticDataMemberDeclaration() const
StringRef getLinkageName() const
Tagged DWARF-like metadata node.
LLVM_ABI dwarf::Tag getTag() const
Base class for scope-like contexts.
Subprogram description. Uses SubclassData1.
Type array for a subprogram.
StringRef getName() const
bool isForwardDecl() const
uint64_t getSizeInBits() const
DIScope * getScope() const
StringRef getName() const
Base class for non-instruction debug metadata records that have positions within IR.
const MachineInstr * CurMI
If nonnull, stores the current machine instruction we're processing.
AsmPrinter * Asm
Target of debug info emission.
DebugHandlerBase(AsmPrinter *A)
void beginModule(Module *M) override
Utility to find all debug info in a module.
LLVM_ABI void processModule(const Module &M)
Process entire module and collect debug info anchors.
iterator_range< global_variable_expression_iterator > global_variables() const
iterator_range< subprogram_iterator > subprograms() const
iterator_range< type_iterator > types() const
ValueT lookup(const_arg_type_t< KeyT > Val) const
Return the entry for the specified key, or a default constructed value if no such entry exists.
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Attribute getFnAttribute(Attribute::AttrKind Kind) const
Return the attribute for the given attribute kind.
DISubprogram * getSubprogram() const
Get the attached subprogram.
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
constexpr unsigned id() const
Tracking metadata reference owned by Metadata.
bool equalsStr(StringRef Str) const
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineBasicBlock & front() const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
A Module instance is used to store all the information related to an LLVM module.
void beginInstruction(const MachineInstr *MI) override
Process beginning of an instruction.
void emitNonSemanticDebugStrings(SPIRV::ModuleAnalysisInfo &MAI)
Emit OpString instructions for all NSDI file paths and basic type names into the debug section (secti...
void beginModule(Module *M) override
Collect compile-unit metadata from the module.
void endFunctionImpl(const MachineFunction *MF) override
void beginFunctionImpl(const MachineFunction *MF) override
void emitNonSemanticGlobalDebugInfo(SPIRV::ModuleAnalysisInfo &MAI)
Emit module-scope NSDI instructions (DebugSource, DebugCompilationUnit, DebugTypeBasic,...
void prepareModuleOutput(const SPIRVSubtarget &ST, SPIRV::ModuleAnalysisInfo &MAI)
Add SPV_KHR_non_semantic_info extension and NonSemantic.Shader.DebugInfo.100 ext inst set entry to MA...
SPIRVNonSemanticDebugHandler(AsmPrinter &AP)
void endInstruction() override
Process end of an instruction.
void notifyEntryLabelEmitted(const MachineFunction &MF)
Called after the synthesized entry OpLabel has been emitted.
A vector that has set insertion semantics.
bool insert(const value_type &X)
Insert a new element into the SetVector.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
void assign(StringRef RHS)
Assign from a StringRef.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
LLVM Value Representation.
Scope
Defines the scope in which this symbol should be visible: Default – Visible in the public interface o...
LLVM_ABI bool is_absolute(const Twine &path, Style style=Style::native)
Is path absolute?
LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
This is an optimization pass for GlobalISel generic memory operations.
detail::zippy< detail::zip_shortest, T, U, Args... > zip(T &&t, U &&u, Args &&...args)
zip iterator for two or more iteratable types.
UnaryFunction for_each(R &&Range, UnaryFunction F)
Provide wrappers to std::for_each which take ranges instead of having to pass begin/end explicitly.
void addStringImm(StringRef Str, MCInst &Inst)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
auto map_to_vector(ContainerTy &&C, FuncTy &&F)
Map a range to a SmallVector with element types deduced from the mapping.
auto dyn_cast_if_present(const Y &Val)
dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a null (or none in the case ...
LLVM_ABI void reportFatalInternalError(Error Err)
Report a fatal error that indicates a bug in LLVM.
detail::concat_range< ValueT, RangeTs... > concat(RangeTs &&...Ranges)
Returns a concatenated range across two or more ranges.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
auto dyn_cast_or_null(const Y &Val)
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...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
MCRegister getExtInstSetReg(unsigned SetNum)
DenseMap< unsigned, MCRegister > ExtInstSetMap
InstrList & getMSInstrs(unsigned MSType)
MCRegister getRegisterAlias(const MachineFunction *MF, Register Reg)
bool getSkipEmission(const MachineInstr *MI)
MCRegister getGlobalObjReg(const GlobalObject *GO)
MCRegister getNextIDRegister()
void addExtension(Extension::Extension ToAdd)