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())
301 CompileUnits.clear();
303 PointerTypes.clear();
304 SubroutineTypes.clear();
307 CompositeTypes.clear();
308 TypedefTypes.clear();
309 SubprogramDeclarations.clear();
310 SubprogramDefinitions.clear();
311 UniqueDebugLocations.clear();
312 GlobalVariableDebugInfoMap.clear();
313 LexicalBlocks.clear();
314 DebugScopeRegs.clear();
315 ScopeToPathOpStringReg.clear();
316 DebugSourceRegByFileStr.clear();
317 OpStringContentCache.clear();
318 I32ConstantCache.clear();
319 DebugTypeFunctionCache.clear();
320 GlobalDIEmitted =
false;
321 GlobalNSDIEnabled =
false;
322 CurrentMAI =
nullptr;
324 NonSemanticOpStringsSectionEmitted =
false;
334 CompileUnitInfo Info;
337 Info.FilePath = File->getFilename();
340 File->getFilename());
343 Info.SpirvSourceLanguage = toNSDISrcLang(
CU->getSourceLanguage().getName());
344 CompileUnits.push_back(std::move(Info));
350 if (
const NamedMDNode *Flags = M->getNamedMetadata(
"llvm.module.flags")) {
351 for (
const auto *
Op : Flags->operands()) {
365 partitionTypes(Ty, BasicTypes, PointerTypes, SubroutineTypes, VectorTypes,
366 ArrayTypes, CompositeTypes, TypedefTypes);
370 if (SP->isDefinition())
371 SubprogramDefinitions.push_back(SP);
373 SubprogramDeclarations.push_back(SP);
380 G.getDebugInfo(GVEs);
391 GlobalVariableDebugInfoMap.try_emplace(
392 GV, GlobalVariableDebugInfo{Expr, DIGVToLLVMGV.
lookup(GV)});
406 if (CompileUnits.empty())
408 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_non_semantic_info))
421void SPIRVNonSemanticDebugHandler::emitMCInst(
MCInst &Inst) {
426SPIRVNonSemanticDebugHandler::emitOpString(
StringRef S,
437MCRegister SPIRVNonSemanticDebugHandler::emitOpStringIfNew(
440 assert(!NonSemanticOpStringsSectionEmitted &&
441 "emitOpStringIfNew is only valid while emitting SPIR-V section 7");
443 auto [It,
Inserted] = OpStringContentCache.try_emplace(S, MCRegister());
445 It->second = emitOpString(S, MAI);
452 assert(NonSemanticOpStringsSectionEmitted &&
453 "getCachedOpStringReg requires emitNonSemanticDebugStrings() first");
455 auto It = OpStringContentCache.find(S);
456 assert(It != OpStringContentCache.end() &&
457 "NSDI OpString missing from cache; emitNonSemanticDebugStrings must "
458 "cache every string used in section 10");
462MCRegister SPIRVNonSemanticDebugHandler::emitAndCacheScopePathOpStringReg(
464 auto [It,
Inserted] = ScopeToPathOpStringReg.try_emplace(Scope, MCRegister());
466 It->second = emitOpStringIfNew(getDebugFullPath(Scope), MAI);
470MCRegister SPIRVNonSemanticDebugHandler::getCachedScopePathOpStringReg(
471 const DIScope *Scope,
bool UseEmptyPathIfNullScope) {
473 assert(UseEmptyPathIfNullScope &&
474 "null scope path lookup requires UseEmptyPathIfNullScope");
475 assert(CachedEmptyStringReg.isValid() &&
476 "empty path OpString must be cached in emitNonSemanticDebugStrings");
477 return CachedEmptyStringReg;
479 auto It = ScopeToPathOpStringReg.find(Scope);
480 assert(It != ScopeToPathOpStringReg.end() &&
481 "path OpString must be cached in emitNonSemanticDebugStrings");
482 MCRegister FileStrReg = It->second;
483 assert(FileStrReg.
isValid() &&
"path OpString id must be valid once cached");
487MCRegister SPIRVNonSemanticDebugHandler::emitOpConstantI32(
504MCRegister SPIRVNonSemanticDebugHandler::emitExtInst(
505 SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
521MCRegister SPIRVNonSemanticDebugHandler::getOrEmitDebugTypeFunction(
529 MCRegister
Reg = emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeFunction,
530 VoidTypeReg, ExtInstSetReg,
Ops, MAI);
535MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeVoidReg(
537 if (!CachedOpTypeVoidReg.isValid())
538 CachedOpTypeVoidReg = findOrEmitOpTypeVoid(MAI);
539 return CachedOpTypeVoidReg;
542MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeInt32Reg(
544 if (!CachedOpTypeInt32Reg.isValid())
545 CachedOpTypeInt32Reg = findOrEmitOpTypeInt32(MAI);
546 return CachedOpTypeInt32Reg;
549MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeVoid(
552 if (
MI->getOpcode() == SPIRV::OpTypeVoid)
563MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeInt32(
566 if (
MI->getOpcode() == SPIRV::OpTypeInt &&
567 MI->getOperand(1).getImm() == 32 &&
MI->getOperand(2).getImm() == 0)
580std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypePointer(
585 if (!PT->getDWARFAddressSpace().has_value())
588 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
589 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
590 MCRegister DebugTypePointerFlagsReg =
591 emitOpConstantI32(transDebugFlags(PT), I32TypeReg, MAI);
595 const auto &
ST =
static_cast<const SPIRVSubtarget &
>(
Asm->getSubtargetInfo());
596 MCRegister StorageClassReg = emitOpConstantI32(
600 if (
const DIType *BaseTy = PT->getBaseType()) {
601 auto BaseIt = DebugScopeRegs.find(BaseTy);
602 if (BaseIt != DebugScopeRegs.end())
604 SPIRV::NonSemanticExtInst::DebugTypePointer, VoidTypeReg,
606 {BaseIt->second, StorageClassReg, DebugTypePointerFlagsReg}, MAI);
615 SPIRV::NonSemanticExtInst::DebugTypePointer, VoidTypeReg, ExtInstSetReg,
616 {CachedDebugInfoNoneReg, StorageClassReg, DebugTypePointerFlagsReg}, MAI);
619std::optional<MCRegister>
620SPIRVNonSemanticDebugHandler::emitDebugTypeFunctionForSubroutineType(
623 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
624 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
625 MCRegister DebugTypeFunctionFlagsReg =
626 emitOpConstantI32(transDebugFlags(ST), I32TypeReg, MAI);
627 DITypeArray
TA =
ST->getTypeArray();
629 Ops.push_back(DebugTypeFunctionFlagsReg);
634 Ops.push_back(VoidTypeReg);
636 for (
unsigned I = 0,
E =
TA.size();
I !=
E; ++
I) {
637 bool IsReturnType = (
I == 0);
638 auto OptReg = mapDISignatureTypeToReg(TA[
I], VoidTypeReg, IsReturnType);
643 Ops.push_back(*OptReg);
646 return getOrEmitDebugTypeFunction(
Ops, VoidTypeReg, ExtInstSetReg, MAI);
650std::optional<MCRegister> SPIRVNonSemanticDebugHandler::resolveScope(
654 return lookupOptReg(DebugScopeRegs, Scope);
658 return lookupOptReg(DebugScopeRegs, FallbackCU);
660 if (CompileUnits.empty())
663 return lookupOptReg(DebugScopeRegs, CompileUnits[0].TheCU);
666std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugLexicalBlock(
670 "S must be a DILexicalBlock or DINamespace in emitDebugLexicalBlock");
671 auto ParentRegOpt = resolveScope(S->
getScope());
675 MCRegister FileStrReg = getCachedScopePathOpStringReg(
677 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
682 MCRegister LineReg = emitOpConstantI32(
static_cast<uint32_t
>(LB->getLine()),
684 MCRegister ColReg = emitOpConstantI32(
685 static_cast<uint32_t
>(LB->getColumn()), I32TypeReg, MAI);
686 Ops = {SrcReg, LineReg, ColReg, *ParentRegOpt};
690 MCRegister LineReg = emitOpConstantI32(0, I32TypeReg, MAI);
691 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
692 MCRegister NameReg = getCachedOpStringReg(NS->getName());
693 Ops = {SrcReg, LineReg, ColReg, *ParentRegOpt, NameReg};
696 return emitExtInst(SPIRV::NonSemanticExtInst::DebugLexicalBlock, VoidTypeReg,
697 ExtInstSetReg,
Ops, MAI);
700std::optional<MCRegister>
701SPIRVNonSemanticDebugHandler::emitDebugFunctionDeclaration(
704 assert(SP &&
"SP must not be null in emitDebugFunctionDeclaration");
706 "SP must not be a definition in emitDebugFunctionDeclaration");
709 const DISubroutineType *
ST =
SP->getType();
711 auto FnTyRegOpt = lookupOptReg(DebugScopeRegs, ST);
714 MCRegister FnTyReg = *FnTyRegOpt;
716 auto ParentRegOpt = resolveScope(
SP->getScope(),
SP->getUnit());
720 MCRegister ParentReg = *ParentRegOpt;
722 MCRegister FileStrReg = getCachedScopePathOpStringReg(SP);
724 MCRegister NameReg = getCachedOpStringReg(
SP->getName());
725 MCRegister LinkageReg = getCachedOpStringReg(
SP->getLinkageName());
726 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
730 emitOpConstantI32(
static_cast<uint32_t
>(
SP->getLine()), I32TypeReg, MAI);
731 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
733 uint32_t FlagsVal = transDebugFlags(SP);
736 FlagsVal &= ~NSDIFlagIsDefinition;
737 MCRegister FlagsReg = emitOpConstantI32(FlagsVal, I32TypeReg, MAI);
739 return emitExtInst(SPIRV::NonSemanticExtInst::DebugFunctionDeclaration,
740 VoidTypeReg, ExtInstSetReg,
741 {NameReg, FnTyReg, SrcReg, LineReg, ColReg, ParentReg,
742 LinkageReg, FlagsReg},
746std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugFunction(
749 assert(SP &&
"SP must not be null in emitDebugFunction");
750 assert(
SP->isDefinition() &&
"SP must be a definition in emitDebugFunction");
752 const DISubroutineType *
ST =
SP->getType();
753 auto FnTyRegOpt = lookupOptReg(DebugScopeRegs, ST);
757 auto ParentRegOpt = resolveScope(
SP->getScope(),
SP->getUnit());
761 MCRegister NameReg = getCachedOpStringReg(
SP->getName());
762 MCRegister LinkageReg = getCachedOpStringReg(
SP->getLinkageName());
763 MCRegister FileStrReg = getCachedScopePathOpStringReg(SP);
764 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
768 emitOpConstantI32(
static_cast<uint32_t
>(
SP->getLine()), I32TypeReg, MAI);
771 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
772 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(SP), I32TypeReg, MAI);
773 MCRegister ScopeLineReg = emitOpConstantI32(
774 static_cast<uint32_t
>(
SP->getScopeLine()), I32TypeReg, MAI);
777 LineReg, ColReg, *ParentRegOpt,
778 LinkageReg, FlagsReg, ScopeLineReg};
780 if (
const DISubprogram *Decl =
SP->getDeclaration()) {
781 if (
auto DeclRegOpt = lookupOptReg(DebugScopeRegs, Decl))
782 Ops.push_back(*DeclRegOpt);
785 return emitExtInst(SPIRV::NonSemanticExtInst::DebugFunction, VoidTypeReg,
786 ExtInstSetReg,
Ops, MAI);
789std::optional<MCRegister> SPIRVNonSemanticDebugHandler::mapDISignatureTypeToReg(
794 assert(CachedDebugInfoNoneReg.isValid() &&
795 "DebugInfoNone must be emitted before DISubroutineType operands");
796 return CachedDebugInfoNoneReg;
798 return lookupOptReg(DebugScopeRegs, Ty);
802std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugExpression(
807std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugGlobalVariable(
811 assert(GV &&
"GV must not be null in emitDebugGlobalVariable");
813 auto ParentRegOpt = resolveScope(GV->
getScope());
817 MCRegister ParentReg = *ParentRegOpt;
823 MCRegister TyReg = CachedDebugInfoNoneReg;
824 if (
const DIType *Ty = GV->
getType()) {
825 auto TyRegOpt = lookupOptReg(DebugScopeRegs, Ty);
831 std::optional<MCRegister> StaticMemberRegOpt;
833 StaticMemberRegOpt = lookupOptReg(DebugScopeRegs, SM);
834 if (!StaticMemberRegOpt)
838 MCRegister NameReg = getCachedOpStringReg(GV->
getName());
839 MCRegister LinkageReg = getCachedOpStringReg(GV->
getLinkageName());
840 MCRegister FileStrReg = getCachedScopePathOpStringReg(
842 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
846 emitOpConstantI32(
static_cast<uint32_t
>(GV->
getLine()), I32TypeReg, MAI);
850 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
854 MCRegister VariableReg = CachedDebugInfoNoneReg;
855 if (
const GlobalVariable *LLVMGV =
Info.LLVMGV) {
859 }
else if (
Info.Expr) {
861 emitDebugExpression(
Info.Expr, VoidTypeReg, ExtInstSetReg, MAI))
862 VariableReg = *ExprReg;
865 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(GV), I32TypeReg, MAI);
868 LineReg, ColReg, ParentReg,
869 LinkageReg, VariableReg, FlagsReg};
871 if (StaticMemberRegOpt)
872 Ops.push_back(*StaticMemberRegOpt);
874 return emitExtInst(SPIRV::NonSemanticExtInst::DebugGlobalVariable,
875 VoidTypeReg, ExtInstSetReg,
Ops, MAI);
878std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeVector(
884 auto BTIt = DebugScopeRegs.find(BaseTy);
885 if (BTIt == DebugScopeRegs.end())
898 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
899 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
900 MCRegister CountReg = emitOpConstantI32(
901 static_cast<uint32_t
>(CI->getZExtValue()), I32TypeReg, MAI);
902 return emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeVector, VoidTypeReg,
903 ExtInstSetReg, {BTIt->second, CountReg}, MAI);
906std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeArray(
911 auto BaseRegOpt = lookupOptReg(DebugScopeRegs, AT->
getBaseType());
915 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
916 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
919 Ops.push_back(*BaseRegOpt);
935 const APInt &
Value = CI->getValue();
936 if (
Value.getActiveBits() <= 32)
937 Count =
static_cast<uint32_t
>(
Value.getZExtValue());
939 Ops.push_back(emitOpConstantI32(
Count, I32TypeReg, MAI));
942 return emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeArray, VoidTypeReg,
943 ExtInstSetReg,
Ops, MAI);
946std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeMember(
950 auto TyRegOpt = lookupOptReg(DebugScopeRegs,
M->getBaseType());
954 MCRegister NameReg = getCachedOpStringReg(
M->getName());
955 MCRegister FileStrReg = getCachedScopePathOpStringReg(
957 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
960 emitOpConstantI32(
static_cast<uint32_t
>(
M->getLine()), I32TypeReg, MAI);
963 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
964 MCRegister OffsetReg = emitOpConstantI32(
965 static_cast<uint32_t
>(
M->getOffsetInBits()), I32TypeReg, MAI);
966 MCRegister SizeReg = emitOpConstantI32(
967 static_cast<uint32_t
>(
M->getSizeInBits()), I32TypeReg, MAI);
968 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(M), I32TypeReg, MAI);
979 return emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeMember, VoidTypeReg,
981 {NameReg, *TyRegOpt, SrcReg, LineReg, ColReg, OffsetReg,
986std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeComposite(
990 auto ParentRegOpt = resolveScope(CT->
getScope());
994 MCRegister NameReg = getCachedOpStringReg(CT->
getName());
995 MCRegister LinkageReg = getCachedOpStringReg(CT->
getIdentifier());
996 MCRegister FileStrReg = getCachedScopePathOpStringReg(
998 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1002 emitOpConstantI32(mapCompositeTypeTag(CT->
getTag()), I32TypeReg, MAI);
1003 MCRegister LineReg =
1004 emitOpConstantI32(
static_cast<uint32_t
>(CT->
getLine()), I32TypeReg, MAI);
1005 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
1008 MCRegister SizeReg = CachedDebugInfoNoneReg;
1010 SizeReg = emitOpConstantI32(
static_cast<uint32_t
>(CT->
getSizeInBits()),
1013 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(CT), I32TypeReg, MAI);
1016 LineReg, ColReg, *ParentRegOpt,
1017 LinkageReg, SizeReg, FlagsReg};
1019 return emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeComposite, VoidTypeReg,
1020 ExtInstSetReg,
Ops, MAI);
1023std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypedef(
1027 auto BaseRegOpt = lookupOptReg(DebugScopeRegs, TD->getBaseType());
1029 return std::nullopt;
1031 MCRegister NameReg = getCachedOpStringReg(TD->
getName());
1032 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1034 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1035 ExtInstSetReg, MAI);
1036 MCRegister LineReg =
1037 emitOpConstantI32(
static_cast<uint32_t
>(TD->
getLine()), I32TypeReg, MAI);
1039 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
1044 auto ParentRegOpt = resolveScope(TD->
getScope());
1046 return std::nullopt;
1047 MCRegister ParentReg = *ParentRegOpt;
1050 SPIRV::NonSemanticExtInst::DebugTypedef, VoidTypeReg, ExtInstSetReg,
1051 {NameReg, *BaseRegOpt, SrcReg, LineReg, ColReg, ParentReg}, MAI);
1056 if (CompileUnits.empty())
1064 for (
const CompileUnitInfo &Info : CompileUnits) {
1066 MCRegister PathReg = emitOpStringIfNew(Info.FilePath, MAI);
1067 ScopeToPathOpStringReg[Info.TheCU] = PathReg;
1068 if (
const DIFile *
F = Info.TheCU->getFile())
1069 ScopeToPathOpStringReg[
F] = PathReg;
1074 emitOpStringIfNew(
BT->getName(), MAI);
1077 SubprogramDeclarations, SubprogramDefinitions)) {
1078 emitOpStringIfNew(SP->getName(), MAI);
1079 emitOpStringIfNew(SP->getLinkageName(), MAI);
1080 emitAndCacheScopePathOpStringReg(SP, MAI);
1087 emitOpStringIfNew(CT->
getName(), MAI);
1089 emitAndCacheScopePathOpStringReg(CT->
getFile(), MAI);
1092 if (!M || M->getTag() != dwarf::DW_TAG_member)
1094 emitOpStringIfNew(M->getName(), MAI);
1095 emitAndCacheScopePathOpStringReg(M->getFile(), MAI);
1101 emitOpStringIfNew(TD->
getName(), MAI);
1102 emitAndCacheScopePathOpStringReg(TD->
getFile(), MAI);
1105 for (
const auto &[GV,
_] : GlobalVariableDebugInfoMap) {
1106 emitOpStringIfNew(GV->
getName(), MAI);
1108 emitAndCacheScopePathOpStringReg(GV->
getFile(), MAI);
1113 for (
const DIScope *S : LexicalBlocks) {
1114 emitAndCacheScopePathOpStringReg(S->
getFile(), MAI);
1116 emitOpStringIfNew(NS->getName(), MAI);
1120 emitAndCacheScopePathOpStringReg(
DL->getScope(), MAI);
1122 CachedEmptyStringReg = emitOpStringIfNew(
"", MAI);
1125 NonSemanticOpStringsSectionEmitted =
true;
1129void SPIRVNonSemanticDebugHandler::emitDebugFunctionDefinition(
1133 "DebugFunctionDefinition operands must be valid");
1134 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
1136 emitExtInst(SPIRV::NonSemanticExtInst::DebugFunctionDefinition, VoidTypeReg,
1137 ExtInstSetReg, {DebugFunctionReg, OpFunctionReg}, MAI);
1140void SPIRVNonSemanticDebugHandler::resetPerFunctionDebugState() {
1141 CurrentMF =
nullptr;
1142 LastFunctionOpVariable =
nullptr;
1143 DebugFunctionDefinitionEmitted =
false;
1144 LastLineMI =
nullptr;
1147void SPIRVNonSemanticDebugHandler::preparePerFunctionDebug(
1149 resetPerFunctionDebugState();
1150 if (!GlobalNSDIEnabled || !CurrentMAI)
1161 if (!SP || !
SP->isDefinition())
1166 LastFunctionOpVariable =
1167 findLastFunctionOpVariableDeclaration(*MF, *CurrentMAI);
1170void SPIRVNonSemanticDebugHandler::tryEmitDebugFunctionDefinition(
1172 if (DebugFunctionDefinitionEmitted || !GlobalNSDIEnabled)
1175 assert(CurrentMF &&
"no current MachineFunction");
1176 const Function &
F = CurrentMF->getFunction();
1177 const DISubprogram *
SP =
F.getSubprogram();
1178 if (!SP || !
SP->isDefinition())
1181 auto DFIt = DebugScopeRegs.find(SP);
1182 if (DFIt == DebugScopeRegs.end())
1189 emitDebugFunctionDefinition(DFIt->second, OpFunctionReg, MAI);
1190 DebugFunctionDefinitionEmitted =
true;
1195 preparePerFunctionDebug(MF);
1200 resetPerFunctionDebugState();
1207 if (!DebugFunctionDefinitionEmitted)
1209 emitDebugLineForInstruction(
MI);
1213 return Opcode == SPIRV::OpSelectionMerge || Opcode == SPIRV::OpLoopMerge ||
1214 Opcode == SPIRV::OpLoopControlINTEL;
1221 switch (
MI->getOpcode()) {
1222 case SPIRV::OpFunction:
1223 case SPIRV::OpFunctionParameter:
1224 case SPIRV::OpFunctionEnd:
1225 case SPIRV::OpLabel:
1237 :
MI->getPrevNode();
1238 Adj; Adj = Forward ? Adj->getNextNode() : Adj->getPrevNode()) {
1246void SPIRVNonSemanticDebugHandler::emitDebugLineForInstruction(
1248 assert(DebugFunctionDefinitionEmitted &&
1249 "DebugFunctionDefinition must be emitted");
1250 assert(CurrentMAI &&
"CurrentMAI must be set");
1252 SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI;
1270 assert(
MI &&
"Merge instruction must be followed by a terminator");
1274 if (LastLineMI &&
MI->getParent() != LastLineMI->getParent())
1275 LastLineMI =
nullptr;
1277 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
1280 const DILocation *
DL =
MI->getDebugLoc().get();
1285 emitExtInst(SPIRV::NonSemanticExtInst::DebugNoLine, VoidTypeReg,
1286 ExtInstSetReg, {}, MAI);
1287 LastLineMI =
nullptr;
1297 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1298 DL->getScope(),
true);
1299 unsigned Line =
DL->getLine();
1300 unsigned Col =
DL->getColumn();
1302 MCRegister SrcReg = DebugSourceRegByFileStr.lookup(FileStrReg.
id());
1303 MCRegister LineReg = I32ConstantCache.lookup(Line);
1304 MCRegister ColStartReg = I32ConstantCache.lookup(Col);
1305 MCRegister ColEndReg = I32ConstantCache.lookup(Col + 1);
1317 if (LastLineMI &&
MI->getDebugLoc() == LastLineMI->getDebugLoc())
1321 emitExtInst(SPIRV::NonSemanticExtInst::DebugLine, VoidTypeReg, ExtInstSetReg,
1322 {SrcReg, LineReg, LineReg, ColStartReg, ColEndReg}, MAI);
1331 if (!
MI || !GlobalNSDIEnabled || DebugFunctionDefinitionEmitted || !CurrentMF)
1334 if (
MI != LastFunctionOpVariable)
1340 assert(CurrentMAI &&
"CurrentMAI must be set");
1341 tryEmitDebugFunctionDefinition(*CurrentMAI);
1346 if (!GlobalNSDIEnabled || DebugFunctionDefinitionEmitted || !CurrentMF)
1349 assert(CurrentMF == &MF &&
1350 "notification does not match the current MachineFunction");
1352 if (LastFunctionOpVariable)
1358 tryEmitDebugFunctionDefinition(*CurrentMAI);
1363 if (GlobalDIEmitted)
1366 GlobalDIEmitted =
true;
1368 if (CompileUnits.empty()) {
1369 GlobalNSDIEnabled =
false;
1375 if (!ExtInstSetReg.
isValid()) {
1376 GlobalNSDIEnabled =
false;
1381 assert(NonSemanticOpStringsSectionEmitted &&
1382 "emitNonSemanticDebugStrings() must run before "
1383 "emitNonSemanticGlobalDebugInfo()");
1388 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
1389 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
1391 CachedDebugInfoNoneReg = emitExtInst(SPIRV::NonSemanticExtInst::DebugInfoNone,
1392 VoidTypeReg, ExtInstSetReg, {}, MAI);
1404 MCRegister DebugInfoVersionReg = emitOpConstantI32(100, I32TypeReg, MAI);
1406 emitOpConstantI32(
static_cast<uint32_t>(DwarfVersion), I32TypeReg, MAI);
1411 map_to_vector(CompileUnits, [&](
const CompileUnitInfo &Info) {
1412 return emitOpConstantI32(Info.SpirvSourceLanguage, I32TypeReg, MAI);
1416 for (
auto [Info, SrcLangReg] :
llvm::zip(CompileUnits, SrcLangRegs)) {
1417 MCRegister FileStrReg = ScopeToPathOpStringReg.lookup(Info.TheCU);
1419 "CU path OpString must be emitted in emitNonSemanticDebugStrings");
1420 MCRegister DebugSourceReg = getOrEmitDebugSourceForFileStrReg(
1421 FileStrReg, VoidTypeReg, ExtInstSetReg, MAI);
1423 SPIRV::NonSemanticExtInst::DebugCompilationUnit, VoidTypeReg,
1425 {DebugInfoVersionReg, DwarfVersionReg, DebugSourceReg, SrcLangReg},
1428 DebugScopeRegs[Info.TheCU] = CUDbgReg;
1433 MCRegister I32ZeroReg = emitOpConstantI32(0, I32TypeReg, MAI);
1436 MCRegister NameReg = getCachedOpStringReg(
BT->getName());
1438 static_cast<uint32_t>(
BT->getSizeInBits()), I32TypeReg, MAI);
1442 unsigned Encoding = 0;
1443 switch (
BT->getEncoding()) {
1444 case dwarf::DW_ATE_address:
1447 case dwarf::DW_ATE_boolean:
1450 case dwarf::DW_ATE_float:
1453 case dwarf::DW_ATE_signed:
1456 case dwarf::DW_ATE_signed_char:
1459 case dwarf::DW_ATE_unsigned:
1462 case dwarf::DW_ATE_unsigned_char:
1466 MCRegister EncodingReg = emitOpConstantI32(Encoding, I32TypeReg, MAI);
1469 SPIRV::NonSemanticExtInst::DebugTypeBasic, VoidTypeReg, ExtInstSetReg,
1470 {NameReg, SizeReg, EncodingReg, I32ZeroReg}, MAI);
1471 DebugScopeRegs[
BT] = BTReg;
1476 if (
auto VecReg = emitDebugTypeVector(VT, ExtInstSetReg, MAI))
1477 DebugScopeRegs[VT] = *VecReg;
1482 if (
auto PtrReg = emitDebugTypePointer(PT, ExtInstSetReg, MAI))
1483 DebugScopeRegs[PT] = *PtrReg;
1490 if (
auto ArrReg = emitDebugTypeArray(AT, ExtInstSetReg, MAI))
1491 DebugScopeRegs[AT] = *ArrReg;
1497 emitDebugTypeFunctionForSubroutineType(ST, ExtInstSetReg, MAI))
1498 DebugScopeRegs[ST] = *FnTyReg;
1510 if (
auto LBReg = emitDebugLexicalBlock(S, VoidTypeReg, I32TypeReg,
1511 ExtInstSetReg, MAI))
1512 DebugScopeRegs[S] = *LBReg;
1522 emitDebugTypedef(TD, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI))
1523 DebugScopeRegs[TD] = *TDReg;
1527 for (
const DISubprogram *SP : SubprogramDeclarations) {
1528 if (
auto DeclReg = emitDebugFunctionDeclaration(SP, VoidTypeReg, I32TypeReg,
1529 ExtInstSetReg, MAI))
1530 DebugScopeRegs[SP] = *DeclReg;
1541 if (!M || M->getTag() != dwarf::DW_TAG_member)
1543 if (
auto MemberReg = emitDebugTypeMember(M, VoidTypeReg, I32TypeReg,
1544 ExtInstSetReg, MAI))
1547 if (
auto CompReg = emitDebugTypeComposite(CT, MemberRegs, VoidTypeReg,
1548 I32TypeReg, ExtInstSetReg, MAI))
1549 DebugScopeRegs[CT] = *CompReg;
1555 emitDebugFunction(SP, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI))
1556 DebugScopeRegs[SP] = *FnReg;
1565 if (
auto LBReg = emitDebugLexicalBlock(S, VoidTypeReg, I32TypeReg,
1566 ExtInstSetReg, MAI))
1567 DebugScopeRegs[S] = *LBReg;
1571 for (
const auto &[GV, Info] : GlobalVariableDebugInfoMap)
1572 emitDebugGlobalVariable(GV, Info, VoidTypeReg, I32TypeReg, ExtInstSetReg,
1576 emitOpConstantI32(
DL->getLine(), I32TypeReg, MAI);
1577 emitOpConstantI32(
DL->getColumn(), I32TypeReg, MAI);
1578 emitOpConstantI32(
DL->getColumn() + 1, I32TypeReg, MAI);
1580 getCachedScopePathOpStringReg(
DL->getScope(),
1582 getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg, ExtInstSetReg,
1586 GlobalNSDIEnabled =
true;
1590SPIRVNonSemanticDebugHandler::getDebugFullPath(
const DIScope *Scope)
const {
1606MCRegister SPIRVNonSemanticDebugHandler::getOrEmitDebugSourceForFileStrReg(
1609 const unsigned Key = FileStrReg.
id();
1610 auto It = DebugSourceRegByFileStr.find(
Key);
1611 if (It != DebugSourceRegByFileStr.end())
1614 MCRegister
DS = emitExtInst(SPIRV::NonSemanticExtInst::DebugSource,
1615 VoidTypeReg, ExtInstSetReg, {FileStrReg}, MAI);
1616 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 void collectLexicalBlockChain(const DIScope *S, SetVector< const DIScope * > &Out)
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.
LLVM_ABI DIScope * getScope() const
Subprogram description. Uses SubclassData1.
Type array for a subprogram.
StringRef getName() const
bool isForwardDecl() const
uint64_t getSizeInBits() const
DIScope * getScope() 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
iterator_range< scope_iterator > scopes() 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 contains(const_arg_type key) const
Check if the SetVector contains the given key.
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)
reverse_iterator rbegin()
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.
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 ...
bool isa_and_nonnull(const Y &Val)
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)
iterator_range< filter_iterator< detail::IterOfRange< RangeT >, PredicateT > > make_filter_range(RangeT &&Range, PredicateT Pred)
Convenience function that takes a range of elements and a predicate, and return a new filter_iterator...
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.
constexpr detail::IsaCheckPredicate< Types... > IsaPred
Function object wrapper for the llvm::isa type check.
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)