36template <
typename MapT>
37static std::optional<MCRegister> lookupOptReg(
const MapT &Map,
38 typename MapT::key_type
Key) {
42 assert(It->second.isValid() &&
"invalid register stored in map");
69 if (CT->getTag() == dwarf::DW_TAG_array_type) {
85 }
else if (CT->getTag() == dwarf::DW_TAG_structure_type ||
86 CT->getTag() == dwarf::DW_TAG_class_type ||
87 CT->getTag() == dwarf::DW_TAG_union_type) {
93 if (DT && DT->getTag() == dwarf::DW_TAG_pointer_type)
95 else if (DT && DT->getTag() == dwarf::DW_TAG_typedef)
100 NSDIFlagIsProtected = 1u << 0,
101 NSDIFlagIsPrivate = 1u << 1,
102 NSDIFlagIsPublic = NSDIFlagIsPrivate | NSDIFlagIsProtected,
103 NSDIFlagIsLocal = 1u << 2,
104 NSDIFlagIsDefinition = 1u << 3,
105 NSDIFlagFwdDecl = 1u << 4,
106 NSDIFlagArtificial = 1u << 5,
107 NSDIFlagExplicit = 1u << 6,
108 NSDIFlagPrototyped = 1u << 7,
109 NSDIFlagObjectPointer = 1u << 8,
110 NSDIFlagStaticMember = 1u << 9,
111 NSDIFlagIndirectVariable = 1u << 10,
112 NSDIFlagLValueReference = 1u << 11,
113 NSDIFlagRValueReference = 1u << 12,
114 NSDIFlagIsOptimized = 1u << 13,
115 NSDIFlagIsEnumClass = 1u << 14,
116 NSDIFlagTypePassByValue = 1u << 15,
117 NSDIFlagTypePassByReference = 1u << 16,
118 NSDIFlagUnknownPhysicalLayout = 1u << 17,
124 Flags |= NSDIFlagIsPublic;
126 Flags |= NSDIFlagIsProtected;
128 Flags |= NSDIFlagIsPrivate;
129 if (DFlags & DINode::FlagFwdDecl)
130 Flags |= NSDIFlagFwdDecl;
131 if (DFlags & DINode::FlagArtificial)
132 Flags |= NSDIFlagArtificial;
133 if (DFlags & DINode::FlagExplicit)
134 Flags |= NSDIFlagExplicit;
135 if (DFlags & DINode::FlagPrototyped)
136 Flags |= NSDIFlagPrototyped;
137 if (DFlags & DINode::FlagObjectPointer)
138 Flags |= NSDIFlagObjectPointer;
139 if (DFlags & DINode::FlagStaticMember)
140 Flags |= NSDIFlagStaticMember;
141 if (DFlags & DINode::FlagLValueReference)
142 Flags |= NSDIFlagLValueReference;
143 if (DFlags & DINode::FlagRValueReference)
144 Flags |= NSDIFlagRValueReference;
145 if (DFlags & DINode::FlagTypePassByValue)
146 Flags |= NSDIFlagTypePassByValue;
147 if (DFlags & DINode::FlagTypePassByReference)
148 Flags |= NSDIFlagTypePassByReference;
149 if (DFlags & DINode::FlagEnumClass)
150 Flags |= NSDIFlagIsEnumClass;
157 if (GV->isLocalToUnit())
158 Flags |= NSDIFlagIsLocal;
159 if (GV->isDefinition())
160 Flags |= NSDIFlagIsDefinition;
163 if (SP->isLocalToUnit())
164 Flags |= NSDIFlagIsLocal;
165 if (SP->isOptimized())
166 Flags |= NSDIFlagIsOptimized;
167 if (SP->isDefinition())
168 Flags |= NSDIFlagIsDefinition;
169 Flags |= mapDIFlagsToNonSemantic(SP->getFlags());
171 if (DN->
getTag() == dwarf::DW_TAG_reference_type)
172 Flags |= NSDIFlagLValueReference;
173 if (DN->
getTag() == dwarf::DW_TAG_rvalue_reference_type)
174 Flags |= NSDIFlagRValueReference;
176 Flags |= mapDIFlagsToNonSemantic(Ty->getFlags());
178 Flags |= mapDIFlagsToNonSemantic(LV->getFlags());
184static uint32_t mapCompositeTypeTag(
unsigned Tag) {
186 case dwarf::DW_TAG_class_type:
188 case dwarf::DW_TAG_structure_type:
190 case dwarf::DW_TAG_union_type:
194 ". Expecting 0, 1 or 2");
209 bool SeenOpVariable =
false;
211 if (
MI.getOpcode() == SPIRV::OpVariable) {
212 SeenOpVariable =
true;
214 LastOpVariable = &
MI;
218 bool CanInterleaveWithOpVariable =
219 MI.getOpcode() == SPIRV::OpLine ||
MI.getOpcode() == SPIRV::OpNoLine;
220 if (SeenOpVariable && !CanInterleaveWithOpVariable &&
224 return LastOpVariable;
235unsigned SPIRVNonSemanticDebugHandler::toNSDISrcLang(
unsigned DwarfSrcLang) {
236 switch (DwarfSrcLang) {
237 case dwarf::DW_LANG_OpenCL:
239 case dwarf::DW_LANG_OpenCL_CPP:
241 case dwarf::DW_LANG_CPP_for_OpenCL:
243 case dwarf::DW_LANG_GLSL:
245 case dwarf::DW_LANG_HLSL:
247 case dwarf::DW_LANG_SYCL:
249 case dwarf::DW_LANG_Zig:
264 CompileUnits.clear();
266 PointerTypes.clear();
267 SubroutineTypes.clear();
270 CompositeTypes.clear();
271 TypedefTypes.clear();
272 SubprogramDeclarations.clear();
273 SubprogramDefinitions.clear();
274 GlobalVariableDebugInfoMap.clear();
275 DebugFunctionDeclarationRegs.clear();
276 DebugFunctionRegs.clear();
277 ScopeToPathOpStringReg.clear();
278 CUToCompilationUnitDbgReg.clear();
279 DebugSourceRegByFileStr.clear();
280 DebugTypeRegs.clear();
281 OpStringContentCache.clear();
282 I32ConstantCache.clear();
283 DebugTypeFunctionCache.clear();
284 GlobalDIEmitted =
false;
285 GlobalNSDIEnabled =
false;
286 CurrentMAI =
nullptr;
288 NonSemanticOpStringsSectionEmitted =
false;
298 CompileUnitInfo Info;
301 Info.FilePath = File->getFilename();
304 File->getFilename());
307 Info.SpirvSourceLanguage = toNSDISrcLang(
CU->getSourceLanguage().getName());
308 CompileUnits.push_back(std::move(Info));
314 if (
const NamedMDNode *Flags = M->getNamedMetadata(
"llvm.module.flags")) {
315 for (
const auto *
Op : Flags->operands()) {
329 partitionTypes(Ty, BasicTypes, PointerTypes, SubroutineTypes, VectorTypes,
330 ArrayTypes, CompositeTypes, TypedefTypes);
334 if (SP->isDefinition())
335 SubprogramDefinitions.push_back(SP);
337 SubprogramDeclarations.push_back(SP);
344 G.getDebugInfo(GVEs);
355 GlobalVariableDebugInfoMap.try_emplace(
356 GV, GlobalVariableDebugInfo{Expr, DIGVToLLVMGV.
lookup(GV)});
362 if (CompileUnits.empty())
364 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_non_semantic_info))
377void SPIRVNonSemanticDebugHandler::emitMCInst(
MCInst &Inst) {
382SPIRVNonSemanticDebugHandler::emitOpString(
StringRef S,
393MCRegister SPIRVNonSemanticDebugHandler::emitOpStringIfNew(
396 assert(!NonSemanticOpStringsSectionEmitted &&
397 "emitOpStringIfNew is only valid while emitting SPIR-V section 7");
399 auto [It,
Inserted] = OpStringContentCache.try_emplace(S, MCRegister());
401 It->second = emitOpString(S, MAI);
408 assert(NonSemanticOpStringsSectionEmitted &&
409 "getCachedOpStringReg requires emitNonSemanticDebugStrings() first");
411 auto It = OpStringContentCache.find(S);
412 assert(It != OpStringContentCache.end() &&
413 "NSDI OpString missing from cache; emitNonSemanticDebugStrings must "
414 "cache every string used in section 10");
418MCRegister SPIRVNonSemanticDebugHandler::emitAndCacheScopePathOpStringReg(
420 auto [It,
Inserted] = ScopeToPathOpStringReg.try_emplace(Scope, MCRegister());
422 It->second = emitOpStringIfNew(getDebugFullPath(Scope), MAI);
426MCRegister SPIRVNonSemanticDebugHandler::getCachedScopePathOpStringReg(
427 const DIScope *Scope,
bool UseEmptyPathIfNullScope) {
429 assert(UseEmptyPathIfNullScope &&
430 "null scope path lookup requires UseEmptyPathIfNullScope");
431 assert(CachedEmptyStringReg.isValid() &&
432 "empty path OpString must be cached in emitNonSemanticDebugStrings");
433 return CachedEmptyStringReg;
435 auto It = ScopeToPathOpStringReg.find(Scope);
436 assert(It != ScopeToPathOpStringReg.end() &&
437 "path OpString must be cached in emitNonSemanticDebugStrings");
438 MCRegister FileStrReg = It->second;
439 assert(FileStrReg.
isValid() &&
"path OpString id must be valid once cached");
443MCRegister SPIRVNonSemanticDebugHandler::emitOpConstantI32(
460MCRegister SPIRVNonSemanticDebugHandler::emitExtInst(
461 SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
471 for (MCRegister R : Operands)
477MCRegister SPIRVNonSemanticDebugHandler::getOrEmitDebugTypeFunction(
485 MCRegister
Reg = emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeFunction,
486 VoidTypeReg, ExtInstSetReg,
Ops, MAI);
491MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeVoidReg(
493 if (!CachedOpTypeVoidReg.isValid())
494 CachedOpTypeVoidReg = findOrEmitOpTypeVoid(MAI);
495 return CachedOpTypeVoidReg;
498MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeInt32Reg(
500 if (!CachedOpTypeInt32Reg.isValid())
501 CachedOpTypeInt32Reg = findOrEmitOpTypeInt32(MAI);
502 return CachedOpTypeInt32Reg;
505MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeVoid(
508 if (
MI->getOpcode() == SPIRV::OpTypeVoid)
519MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeInt32(
522 if (
MI->getOpcode() == SPIRV::OpTypeInt &&
523 MI->getOperand(1).getImm() == 32 &&
MI->getOperand(2).getImm() == 0)
536std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypePointer(
541 if (!PT->getDWARFAddressSpace().has_value())
544 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
545 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
546 MCRegister DebugTypePointerFlagsReg =
547 emitOpConstantI32(transDebugFlags(PT), I32TypeReg, MAI);
551 const auto &
ST =
static_cast<const SPIRVSubtarget &
>(
Asm->getSubtargetInfo());
552 MCRegister StorageClassReg = emitOpConstantI32(
556 if (
const DIType *BaseTy = PT->getBaseType()) {
557 auto BaseIt = DebugTypeRegs.find(BaseTy);
558 if (BaseIt != DebugTypeRegs.end())
560 SPIRV::NonSemanticExtInst::DebugTypePointer, VoidTypeReg,
562 {BaseIt->second, StorageClassReg, DebugTypePointerFlagsReg}, MAI);
571 SPIRV::NonSemanticExtInst::DebugTypePointer, VoidTypeReg, ExtInstSetReg,
572 {CachedDebugInfoNoneReg, StorageClassReg, DebugTypePointerFlagsReg}, MAI);
575std::optional<MCRegister>
576SPIRVNonSemanticDebugHandler::emitDebugTypeFunctionForSubroutineType(
579 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
580 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
581 MCRegister DebugTypeFunctionFlagsReg =
582 emitOpConstantI32(transDebugFlags(ST), I32TypeReg, MAI);
583 DITypeArray
TA =
ST->getTypeArray();
585 Ops.push_back(DebugTypeFunctionFlagsReg);
590 Ops.push_back(VoidTypeReg);
592 for (
unsigned I = 0,
E =
TA.size();
I !=
E; ++
I) {
593 bool IsReturnType = (
I == 0);
594 auto OptReg = mapDISignatureTypeToReg(TA[
I], VoidTypeReg, IsReturnType);
599 Ops.push_back(*OptReg);
602 return getOrEmitDebugTypeFunction(
Ops, VoidTypeReg, ExtInstSetReg, MAI);
606std::optional<MCRegister>
607SPIRVNonSemanticDebugHandler::resolveDebugFunctionParent(
609 const DIScope *
Scope =
SP->getScope();
616 return lookupOptReg(DebugTypeRegs, Ty);
619 const DICompileUnit *ParentCU =
SP->getUnit();
620 if (!ParentCU && !CompileUnits.empty())
621 ParentCU = CompileUnits[0].TheCU;
624 return lookupOptReg(CUToCompilationUnitDbgReg, ParentCU);
627std::optional<MCRegister> SPIRVNonSemanticDebugHandler::resolveTypeScopeParent(
632 return lookupOptReg(DebugTypeRegs, Ty);
636 if (CompileUnits.empty())
639 return lookupOptReg(CUToCompilationUnitDbgReg, CompileUnits[0].TheCU);
642std::optional<MCRegister>
643SPIRVNonSemanticDebugHandler::emitDebugFunctionDeclaration(
646 assert(SP &&
"SP must not be null in emitDebugFunctionDeclaration");
648 "SP must not be a definition in emitDebugFunctionDeclaration");
651 const DISubroutineType *
ST =
SP->getType();
653 auto FnTyRegOpt = lookupOptReg(DebugTypeRegs, ST);
656 MCRegister FnTyReg = *FnTyRegOpt;
658 auto ParentRegOpt = resolveDebugFunctionParent(SP);
662 MCRegister ParentReg = *ParentRegOpt;
664 MCRegister FileStrReg = getCachedScopePathOpStringReg(SP);
666 MCRegister NameReg = getCachedOpStringReg(
SP->getName());
667 MCRegister LinkageReg = getCachedOpStringReg(
SP->getLinkageName());
668 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
672 emitOpConstantI32(
static_cast<uint32_t
>(
SP->getLine()), I32TypeReg, MAI);
673 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
675 uint32_t FlagsVal = transDebugFlags(SP);
678 FlagsVal &= ~NSDIFlagIsDefinition;
679 MCRegister FlagsReg = emitOpConstantI32(FlagsVal, I32TypeReg, MAI);
681 return emitExtInst(SPIRV::NonSemanticExtInst::DebugFunctionDeclaration,
682 VoidTypeReg, ExtInstSetReg,
683 {NameReg, FnTyReg, SrcReg, LineReg, ColReg, ParentReg,
684 LinkageReg, FlagsReg},
688std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugFunction(
691 assert(SP &&
"SP must not be null in emitDebugFunction");
692 assert(
SP->isDefinition() &&
"SP must be a definition in emitDebugFunction");
694 const DISubroutineType *
ST =
SP->getType();
695 auto FnTyRegOpt = lookupOptReg(DebugTypeRegs, ST);
699 auto ParentRegOpt = resolveDebugFunctionParent(SP);
703 MCRegister NameReg = getCachedOpStringReg(
SP->getName());
704 MCRegister LinkageReg = getCachedOpStringReg(
SP->getLinkageName());
705 MCRegister FileStrReg = getCachedScopePathOpStringReg(SP);
706 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
710 emitOpConstantI32(
static_cast<uint32_t
>(
SP->getLine()), I32TypeReg, MAI);
713 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
714 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(SP), I32TypeReg, MAI);
715 MCRegister ScopeLineReg = emitOpConstantI32(
716 static_cast<uint32_t
>(
SP->getScopeLine()), I32TypeReg, MAI);
719 LineReg, ColReg, *ParentRegOpt,
720 LinkageReg, FlagsReg, ScopeLineReg};
722 if (
const DISubprogram *Decl =
SP->getDeclaration()) {
723 if (
auto DeclRegOpt = lookupOptReg(DebugFunctionDeclarationRegs, Decl))
724 Ops.push_back(*DeclRegOpt);
727 return emitExtInst(SPIRV::NonSemanticExtInst::DebugFunction, VoidTypeReg,
728 ExtInstSetReg,
Ops, MAI);
731std::optional<MCRegister> SPIRVNonSemanticDebugHandler::mapDISignatureTypeToReg(
736 assert(CachedDebugInfoNoneReg.isValid() &&
737 "DebugInfoNone must be emitted before DISubroutineType operands");
738 return CachedDebugInfoNoneReg;
740 return lookupOptReg(DebugTypeRegs, Ty);
743MCRegister SPIRVNonSemanticDebugHandler::resolveGlobalVariableParent(
750 assert(!CompileUnits.empty() &&
751 "resolveGlobalVariableParent requires non-empty CompileUnits");
752 std::optional<MCRegister> ParentRegOpt =
753 lookupOptReg(CUToCompilationUnitDbgReg, CompileUnits[0].TheCU);
754 assert(ParentRegOpt &&
"DebugCompilationUnit must be emitted before "
755 "resolveGlobalVariableParent");
757 return *ParentRegOpt;
761std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugExpression(
766std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugGlobalVariable(
770 assert(GV &&
"GV must not be null in emitDebugGlobalVariable");
772 MCRegister ParentReg = resolveGlobalVariableParent(GV);
778 MCRegister TyReg = CachedDebugInfoNoneReg;
779 if (
const DIType *Ty = GV->
getType()) {
780 auto TyRegOpt = lookupOptReg(DebugTypeRegs, Ty);
786 std::optional<MCRegister> StaticMemberRegOpt;
788 StaticMemberRegOpt = lookupOptReg(DebugTypeRegs,
SM);
789 if (!StaticMemberRegOpt)
793 MCRegister NameReg = getCachedOpStringReg(GV->
getName());
794 MCRegister LinkageReg = getCachedOpStringReg(GV->
getLinkageName());
795 MCRegister FileStrReg = getCachedScopePathOpStringReg(
797 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
801 emitOpConstantI32(
static_cast<uint32_t
>(GV->
getLine()), I32TypeReg, MAI);
805 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
809 MCRegister VariableReg = CachedDebugInfoNoneReg;
810 if (
const GlobalVariable *LLVMGV =
Info.LLVMGV) {
814 }
else if (
Info.Expr) {
816 emitDebugExpression(
Info.Expr, VoidTypeReg, ExtInstSetReg, MAI))
817 VariableReg = *ExprReg;
820 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(GV), I32TypeReg, MAI);
823 LineReg, ColReg, ParentReg,
824 LinkageReg, VariableReg, FlagsReg};
826 if (StaticMemberRegOpt)
827 Ops.push_back(*StaticMemberRegOpt);
829 return emitExtInst(SPIRV::NonSemanticExtInst::DebugGlobalVariable,
830 VoidTypeReg, ExtInstSetReg,
Ops, MAI);
833std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeVector(
839 auto BTIt = DebugTypeRegs.find(BaseTy);
840 if (BTIt == DebugTypeRegs.end())
853 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
854 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
855 MCRegister CountReg = emitOpConstantI32(
856 static_cast<uint32_t
>(CI->getZExtValue()), I32TypeReg, MAI);
857 return emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeVector, VoidTypeReg,
858 ExtInstSetReg, {BTIt->second, CountReg}, MAI);
861std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeArray(
866 auto BaseRegOpt = lookupOptReg(DebugTypeRegs, AT->
getBaseType());
870 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
871 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
874 Ops.push_back(*BaseRegOpt);
890 const APInt &
Value = CI->getValue();
891 if (
Value.getActiveBits() <= 32)
892 Count =
static_cast<uint32_t
>(
Value.getZExtValue());
894 Ops.push_back(emitOpConstantI32(
Count, I32TypeReg, MAI));
897 return emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeArray, VoidTypeReg,
898 ExtInstSetReg,
Ops, MAI);
901std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeMember(
905 auto TyRegOpt = lookupOptReg(DebugTypeRegs,
M->getBaseType());
909 MCRegister NameReg = getCachedOpStringReg(
M->getName());
910 MCRegister FileStrReg = getCachedScopePathOpStringReg(
912 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
915 emitOpConstantI32(
static_cast<uint32_t
>(
M->getLine()), I32TypeReg, MAI);
918 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
919 MCRegister OffsetReg = emitOpConstantI32(
920 static_cast<uint32_t
>(
M->getOffsetInBits()), I32TypeReg, MAI);
921 MCRegister SizeReg = emitOpConstantI32(
922 static_cast<uint32_t
>(
M->getSizeInBits()), I32TypeReg, MAI);
923 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(M), I32TypeReg, MAI);
934 return emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeMember, VoidTypeReg,
936 {NameReg, *TyRegOpt, SrcReg, LineReg, ColReg, OffsetReg,
941std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeComposite(
945 auto ParentRegOpt = resolveTypeScopeParent(CT->
getScope());
949 MCRegister NameReg = getCachedOpStringReg(CT->
getName());
950 MCRegister LinkageReg = getCachedOpStringReg(CT->
getIdentifier());
951 MCRegister FileStrReg = getCachedScopePathOpStringReg(
953 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
957 emitOpConstantI32(mapCompositeTypeTag(CT->
getTag()), I32TypeReg, MAI);
959 emitOpConstantI32(
static_cast<uint32_t
>(CT->
getLine()), I32TypeReg, MAI);
960 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
963 MCRegister SizeReg = CachedDebugInfoNoneReg;
965 SizeReg = emitOpConstantI32(
static_cast<uint32_t
>(CT->
getSizeInBits()),
968 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(CT), I32TypeReg, MAI);
971 LineReg, ColReg, *ParentRegOpt,
972 LinkageReg, SizeReg, FlagsReg};
974 return emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeComposite, VoidTypeReg,
975 ExtInstSetReg,
Ops, MAI);
978std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypedef(
982 auto BaseRegOpt = lookupOptReg(DebugTypeRegs, TD->getBaseType());
986 MCRegister NameReg = getCachedOpStringReg(TD->
getName());
987 MCRegister FileStrReg = getCachedScopePathOpStringReg(
989 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
992 emitOpConstantI32(
static_cast<uint32_t
>(TD->
getLine()), I32TypeReg, MAI);
994 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
1002 MCRegister ParentReg;
1004 if (
auto TyRegOpt = lookupOptReg(DebugTypeRegs, Ty))
1005 ParentReg = *TyRegOpt;
1007 assert(!CompileUnits.empty() &&
1008 "emitDebugTypedef requires a compile unit for the Parent operand");
1010 lookupOptReg(CUToCompilationUnitDbgReg, CompileUnits[0].TheCU);
1011 assert(CURegOpt &&
"DebugCompilationUnit must be emitted before typedefs");
1012 ParentReg = *CURegOpt;
1016 SPIRV::NonSemanticExtInst::DebugTypedef, VoidTypeReg, ExtInstSetReg,
1017 {NameReg, *BaseRegOpt, SrcReg, LineReg, ColReg, ParentReg}, MAI);
1022 if (CompileUnits.empty())
1030 for (
const CompileUnitInfo &Info : CompileUnits) {
1032 MCRegister PathReg = emitOpStringIfNew(Info.FilePath, MAI);
1033 ScopeToPathOpStringReg[Info.TheCU] = PathReg;
1034 if (
const DIFile *
F = Info.TheCU->getFile())
1035 ScopeToPathOpStringReg[
F] = PathReg;
1040 emitOpStringIfNew(
BT->getName(), MAI);
1043 SubprogramDeclarations, SubprogramDefinitions)) {
1044 emitOpStringIfNew(SP->getName(), MAI);
1045 emitOpStringIfNew(SP->getLinkageName(), MAI);
1046 emitAndCacheScopePathOpStringReg(SP, MAI);
1053 emitOpStringIfNew(CT->
getName(), MAI);
1055 emitAndCacheScopePathOpStringReg(CT->
getFile(), MAI);
1058 if (!M || M->getTag() != dwarf::DW_TAG_member)
1060 emitOpStringIfNew(M->getName(), MAI);
1061 emitAndCacheScopePathOpStringReg(M->getFile(), MAI);
1067 emitOpStringIfNew(TD->
getName(), MAI);
1068 emitAndCacheScopePathOpStringReg(TD->
getFile(), MAI);
1071 for (
const auto &[GV,
_] : GlobalVariableDebugInfoMap) {
1072 emitOpStringIfNew(GV->
getName(), MAI);
1074 emitAndCacheScopePathOpStringReg(GV->
getFile(), MAI);
1077 CachedEmptyStringReg = emitOpStringIfNew(
"", MAI);
1080 NonSemanticOpStringsSectionEmitted =
true;
1084void SPIRVNonSemanticDebugHandler::emitDebugFunctionDefinition(
1088 "DebugFunctionDefinition operands must be valid");
1089 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
1091 emitExtInst(SPIRV::NonSemanticExtInst::DebugFunctionDefinition, VoidTypeReg,
1092 ExtInstSetReg, {DebugFunctionReg, OpFunctionReg}, MAI);
1095void SPIRVNonSemanticDebugHandler::resetPerFunctionDebugState() {
1096 CurrentMF =
nullptr;
1097 LastFunctionOpVariable =
nullptr;
1098 DebugFunctionDefinitionEmitted =
false;
1101void SPIRVNonSemanticDebugHandler::preparePerFunctionDebug(
1103 resetPerFunctionDebugState();
1104 if (!GlobalNSDIEnabled || !CurrentMAI)
1115 if (!SP || !
SP->isDefinition())
1120 LastFunctionOpVariable =
1121 findLastFunctionOpVariableDeclaration(*MF, *CurrentMAI);
1124void SPIRVNonSemanticDebugHandler::tryEmitDebugFunctionDefinition(
1126 if (DebugFunctionDefinitionEmitted || !GlobalNSDIEnabled)
1129 assert(CurrentMF &&
"no current MachineFunction");
1130 const Function &
F = CurrentMF->getFunction();
1131 const DISubprogram *
SP =
F.getSubprogram();
1132 if (!SP || !
SP->isDefinition())
1135 auto DFIt = DebugFunctionRegs.find(SP);
1136 if (DFIt == DebugFunctionRegs.end())
1143 emitDebugFunctionDefinition(DFIt->second, OpFunctionReg, MAI);
1144 DebugFunctionDefinitionEmitted =
true;
1149 preparePerFunctionDebug(MF);
1154 resetPerFunctionDebugState();
1166 if (!
MI || !GlobalNSDIEnabled || DebugFunctionDefinitionEmitted || !CurrentMF)
1169 if (
MI != LastFunctionOpVariable)
1175 assert(CurrentMAI &&
"CurrentMAI must be set");
1176 tryEmitDebugFunctionDefinition(*CurrentMAI);
1181 if (!GlobalNSDIEnabled || DebugFunctionDefinitionEmitted || !CurrentMF)
1184 assert(CurrentMF == &MF &&
1185 "notification does not match the current MachineFunction");
1187 if (LastFunctionOpVariable)
1193 tryEmitDebugFunctionDefinition(*CurrentMAI);
1198 if (GlobalDIEmitted)
1201 GlobalDIEmitted =
true;
1203 if (CompileUnits.empty()) {
1204 GlobalNSDIEnabled =
false;
1210 if (!ExtInstSetReg.
isValid()) {
1211 GlobalNSDIEnabled =
false;
1216 assert(NonSemanticOpStringsSectionEmitted &&
1217 "emitNonSemanticDebugStrings() must run before "
1218 "emitNonSemanticGlobalDebugInfo()");
1223 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
1224 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
1226 CachedDebugInfoNoneReg = emitExtInst(SPIRV::NonSemanticExtInst::DebugInfoNone,
1227 VoidTypeReg, ExtInstSetReg, {}, MAI);
1239 MCRegister DebugInfoVersionReg = emitOpConstantI32(100, I32TypeReg, MAI);
1241 emitOpConstantI32(
static_cast<uint32_t>(DwarfVersion), I32TypeReg, MAI);
1246 map_to_vector(CompileUnits, [&](
const CompileUnitInfo &Info) {
1247 return emitOpConstantI32(Info.SpirvSourceLanguage, I32TypeReg, MAI);
1251 for (
auto [Info, SrcLangReg] :
llvm::zip(CompileUnits, SrcLangRegs)) {
1252 MCRegister FileStrReg = ScopeToPathOpStringReg.lookup(Info.TheCU);
1254 "CU path OpString must be emitted in emitNonSemanticDebugStrings");
1255 MCRegister DebugSourceReg = getOrEmitDebugSourceForFileStrReg(
1256 FileStrReg, VoidTypeReg, ExtInstSetReg, MAI);
1258 SPIRV::NonSemanticExtInst::DebugCompilationUnit, VoidTypeReg,
1260 {DebugInfoVersionReg, DwarfVersionReg, DebugSourceReg, SrcLangReg},
1263 CUToCompilationUnitDbgReg[Info.TheCU] = CUDbgReg;
1268 MCRegister I32ZeroReg = emitOpConstantI32(0, I32TypeReg, MAI);
1270 DebugTypeRegs.clear();
1273 MCRegister NameReg = getCachedOpStringReg(
BT->getName());
1275 static_cast<uint32_t>(
BT->getSizeInBits()), I32TypeReg, MAI);
1279 unsigned Encoding = 0;
1280 switch (
BT->getEncoding()) {
1281 case dwarf::DW_ATE_address:
1284 case dwarf::DW_ATE_boolean:
1287 case dwarf::DW_ATE_float:
1290 case dwarf::DW_ATE_signed:
1293 case dwarf::DW_ATE_signed_char:
1296 case dwarf::DW_ATE_unsigned:
1299 case dwarf::DW_ATE_unsigned_char:
1303 MCRegister EncodingReg = emitOpConstantI32(Encoding, I32TypeReg, MAI);
1306 SPIRV::NonSemanticExtInst::DebugTypeBasic, VoidTypeReg, ExtInstSetReg,
1307 {NameReg, SizeReg, EncodingReg, I32ZeroReg}, MAI);
1308 DebugTypeRegs[
BT] = BTReg;
1313 if (
auto VecReg = emitDebugTypeVector(VT, ExtInstSetReg, MAI))
1314 DebugTypeRegs[VT] = *VecReg;
1319 if (
auto PtrReg = emitDebugTypePointer(PT, ExtInstSetReg, MAI))
1320 DebugTypeRegs[PT] = *PtrReg;
1327 if (
auto ArrReg = emitDebugTypeArray(AT, ExtInstSetReg, MAI))
1328 DebugTypeRegs[AT] = *ArrReg;
1334 emitDebugTypeFunctionForSubroutineType(ST, ExtInstSetReg, MAI))
1335 DebugTypeRegs[ST] = *FnTyReg;
1345 emitDebugTypedef(TD, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI))
1346 DebugTypeRegs[TD] = *TDReg;
1350 for (
const DISubprogram *SP : SubprogramDeclarations) {
1351 if (
auto DeclReg = emitDebugFunctionDeclaration(SP, VoidTypeReg, I32TypeReg,
1352 ExtInstSetReg, MAI))
1353 DebugFunctionDeclarationRegs[SP] = *DeclReg;
1364 if (!M || M->getTag() != dwarf::DW_TAG_member)
1366 if (
auto MemberReg = emitDebugTypeMember(M, VoidTypeReg, I32TypeReg,
1367 ExtInstSetReg, MAI))
1370 if (
auto CompReg = emitDebugTypeComposite(CT, MemberRegs, VoidTypeReg,
1371 I32TypeReg, ExtInstSetReg, MAI))
1372 DebugTypeRegs[CT] = *CompReg;
1378 emitDebugFunction(SP, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI))
1379 DebugFunctionRegs[SP] = *FnReg;
1383 for (
const auto &[GV, Info] : GlobalVariableDebugInfoMap)
1384 emitDebugGlobalVariable(GV, Info, VoidTypeReg, I32TypeReg, ExtInstSetReg,
1387 GlobalNSDIEnabled =
true;
1391SPIRVNonSemanticDebugHandler::getDebugFullPath(
const DIScope *Scope)
const {
1407MCRegister SPIRVNonSemanticDebugHandler::getOrEmitDebugSourceForFileStrReg(
1410 const unsigned Key = FileStrReg.
id();
1411 auto It = DebugSourceRegByFileStr.find(
Key);
1412 if (It != DebugSourceRegByFileStr.end())
1415 MCRegister
DS = emitExtInst(SPIRV::NonSemanticExtInst::DebugSource,
1416 VoidTypeReg, ExtInstSetReg, {FileStrReg}, MAI);
1417 DebugSourceRegByFileStr[
Key] =
DS;
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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 unsigned SM(unsigned Version)
static constexpr StringLiteral Filename
#define SPIRV_BACKEND_SERVICE_FUN_NAME
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
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.
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.
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)