46template <
typename MapT>
47static std::optional<MCRegister> lookupOptReg(
const MapT &Map,
48 typename MapT::key_type
Key) {
52 assert(It->second.isValid() &&
"invalid register stored in map");
57 NSDIFlagIsProtected = 1u << 0,
58 NSDIFlagIsPrivate = 1u << 1,
59 NSDIFlagIsPublic = NSDIFlagIsPrivate | NSDIFlagIsProtected,
60 NSDIFlagIsLocal = 1u << 2,
61 NSDIFlagIsDefinition = 1u << 3,
62 NSDIFlagFwdDecl = 1u << 4,
63 NSDIFlagArtificial = 1u << 5,
64 NSDIFlagExplicit = 1u << 6,
65 NSDIFlagPrototyped = 1u << 7,
66 NSDIFlagObjectPointer = 1u << 8,
67 NSDIFlagStaticMember = 1u << 9,
68 NSDIFlagIndirectVariable = 1u << 10,
69 NSDIFlagLValueReference = 1u << 11,
70 NSDIFlagRValueReference = 1u << 12,
71 NSDIFlagIsOptimized = 1u << 13,
72 NSDIFlagIsEnumClass = 1u << 14,
73 NSDIFlagTypePassByValue = 1u << 15,
74 NSDIFlagTypePassByReference = 1u << 16,
75 NSDIFlagUnknownPhysicalLayout = 1u << 17,
81 Flags |= NSDIFlagIsPublic;
83 Flags |= NSDIFlagIsProtected;
85 Flags |= NSDIFlagIsPrivate;
86 if (DFlags & DINode::FlagFwdDecl)
87 Flags |= NSDIFlagFwdDecl;
88 if (DFlags & DINode::FlagArtificial)
89 Flags |= NSDIFlagArtificial;
90 if (DFlags & DINode::FlagExplicit)
91 Flags |= NSDIFlagExplicit;
92 if (DFlags & DINode::FlagPrototyped)
93 Flags |= NSDIFlagPrototyped;
94 if (DFlags & DINode::FlagObjectPointer)
95 Flags |= NSDIFlagObjectPointer;
96 if (DFlags & DINode::FlagStaticMember)
97 Flags |= NSDIFlagStaticMember;
98 if (DFlags & DINode::FlagLValueReference)
99 Flags |= NSDIFlagLValueReference;
100 if (DFlags & DINode::FlagRValueReference)
101 Flags |= NSDIFlagRValueReference;
102 if (DFlags & DINode::FlagTypePassByValue)
103 Flags |= NSDIFlagTypePassByValue;
104 if (DFlags & DINode::FlagTypePassByReference)
105 Flags |= NSDIFlagTypePassByReference;
106 if (DFlags & DINode::FlagEnumClass)
107 Flags |= NSDIFlagIsEnumClass;
114 if (GV->isLocalToUnit())
115 Flags |= NSDIFlagIsLocal;
116 if (GV->isDefinition())
117 Flags |= NSDIFlagIsDefinition;
120 if (SP->isLocalToUnit())
121 Flags |= NSDIFlagIsLocal;
122 if (SP->isOptimized())
123 Flags |= NSDIFlagIsOptimized;
124 if (SP->isDefinition())
125 Flags |= NSDIFlagIsDefinition;
126 Flags |= mapDIFlagsToNonSemantic(SP->getFlags());
128 if (DN->
getTag() == dwarf::DW_TAG_reference_type)
129 Flags |= NSDIFlagLValueReference;
130 if (DN->
getTag() == dwarf::DW_TAG_rvalue_reference_type)
131 Flags |= NSDIFlagRValueReference;
133 Flags |= mapDIFlagsToNonSemantic(Ty->getFlags());
135 Flags |= mapDIFlagsToNonSemantic(LV->getFlags());
141static uint32_t mapCompositeTypeTag(
unsigned Tag) {
143 case dwarf::DW_TAG_class_type:
145 case dwarf::DW_TAG_structure_type:
147 case dwarf::DW_TAG_union_type:
151 ". Expecting 0, 1 or 2");
166 bool SeenOpVariable =
false;
168 if (
MI.getOpcode() == SPIRV::OpVariable) {
169 SeenOpVariable =
true;
171 LastOpVariable = &
MI;
175 bool CanInterleaveWithOpVariable =
176 MI.getOpcode() == SPIRV::OpLine ||
MI.getOpcode() == SPIRV::OpNoLine;
177 if (SeenOpVariable && !CanInterleaveWithOpVariable &&
181 return LastOpVariable;
192unsigned SPIRVNonSemanticDebugHandler::toNSDISrcLang(
unsigned DwarfSrcLang) {
193 switch (DwarfSrcLang) {
194 case dwarf::DW_LANG_OpenCL:
196 case dwarf::DW_LANG_OpenCL_CPP:
198 case dwarf::DW_LANG_CPP_for_OpenCL:
200 case dwarf::DW_LANG_GLSL:
202 case dwarf::DW_LANG_HLSL:
204 case dwarf::DW_LANG_SYCL:
206 case dwarf::DW_LANG_Zig:
214 return BT->getEncoding() == dwarf::DW_ATE_boolean;
223 unsigned Width =
BT->getSizeInBits();
232 ?
Value.trunc(std::min(Width, 64u)).getZExtValue()
233 :
Value.getZExtValue(),
246 if (DT->getTag() != dwarf::DW_TAG_typedef || !Seen.
insert(DT).second)
248 Ty = DT->getBaseType();
259 unsigned Size =
BT->getSizeInBits();
260 switch (
BT->getEncoding()) {
261 case dwarf::DW_ATE_signed:
262 case dwarf::DW_ATE_unsigned:
263 case dwarf::DW_ATE_signed_char:
264 case dwarf::DW_ATE_unsigned_char:
266 case dwarf::DW_ATE_float:
292 for (
const MDNode *
N : SP->getRetainedNodes())
297 Locations.insert(
DL);
300 Locations.insert(
DL);
331 CompileUnits.clear();
334 UniqueDebugLocations.clear();
335 GlobalVariableDebugInfoMap.clear();
336 LocalVariables.clear();
337 DebugLocalVariableRegs.clear();
338 DebugExpressionRegs.clear();
339 LexicalBlocks.clear();
340 DebugScopeRegs.clear();
341 ScopesInProgress.clear();
342 FailedScopes.clear();
343 DebugInlinedAtRegs.clear();
344 ScopeToPathOpStringReg.clear();
345 DebugSourceRegByFileStr.clear();
346 OpStringContentCache.clear();
347 ScalarTypeCache.clear();
348 ScalarConstantCache.clear();
349 ConstantValueRegs.clear();
350 DebugOperationCache.clear();
351 DebugExpressionCache.clear();
352 ModuleScopeIds.clear();
353 GlobalDIEmitted =
false;
354 GlobalNSDIEnabled =
false;
355 CurrentMAI =
nullptr;
357 NonSemanticOpStringsSectionEmitted =
false;
367 CompileUnitInfo Info;
370 Info.FilePath = File->getFilename();
373 File->getFilename());
376 Info.SpirvSourceLanguage = toNSDISrcLang(
CU->getSourceLanguage().getName());
377 CompileUnits.push_back(std::move(Info));
383 if (
const NamedMDNode *Flags = M->getNamedMetadata(
"llvm.module.flags")) {
384 for (
const auto *
Op : Flags->operands()) {
399 return Ty->getTag() != dwarf::DW_TAG_member;
408 G.getDebugInfo(GVEs);
419 GlobalVariableDebugInfoMap.try_emplace(
420 GV, GlobalVariableDebugInfo{Expr, DIGVToLLVMGV.
lookup(GV)});
437 if (
MI.getNumOperands() == 0 || !
MI.getOperand(0).isReg() ||
438 !
MI.getOperand(0).isDef())
445 if (CompileUnits.empty())
447 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_non_semantic_info))
461 ModuleScopeIds.insert(Id);
465void SPIRVNonSemanticDebugHandler::emitMCInst(
MCInst &Inst) {
470SPIRVNonSemanticDebugHandler::emitOpString(
StringRef S,
481MCRegister SPIRVNonSemanticDebugHandler::emitOpStringIfNew(
484 assert(!NonSemanticOpStringsSectionEmitted &&
485 "emitOpStringIfNew is only valid while emitting SPIR-V section 7");
487 auto [It,
Inserted] = OpStringContentCache.try_emplace(S, MCRegister());
489 It->second = emitOpString(S, MAI);
496 assert(NonSemanticOpStringsSectionEmitted &&
497 "getCachedOpStringReg requires emitNonSemanticDebugStrings() first");
499 auto It = OpStringContentCache.find(S);
500 assert(It != OpStringContentCache.end() &&
501 "NSDI OpString missing from cache; emitNonSemanticDebugStrings must "
502 "cache every string used in section 10");
506MCRegister SPIRVNonSemanticDebugHandler::emitAndCacheScopePathOpStringReg(
508 auto [It,
Inserted] = ScopeToPathOpStringReg.try_emplace(Scope, MCRegister());
510 It->second = emitOpStringIfNew(getDebugFullPath(Scope), MAI);
514MCRegister SPIRVNonSemanticDebugHandler::getCachedScopePathOpStringReg(
515 const DIScope *Scope,
bool UseEmptyPathIfNullScope) {
517 assert(UseEmptyPathIfNullScope &&
518 "null scope path lookup requires UseEmptyPathIfNullScope");
519 assert(CachedEmptyStringReg.isValid() &&
520 "empty path OpString must be cached in emitNonSemanticDebugStrings");
521 return CachedEmptyStringReg;
523 auto It = ScopeToPathOpStringReg.find(Scope);
524 assert(It != ScopeToPathOpStringReg.end() &&
525 "path OpString must be cached in emitNonSemanticDebugStrings");
526 MCRegister FileStrReg = It->second;
527 assert(FileStrReg.
isValid() &&
"path OpString id must be valid once cached");
531MCRegister SPIRVNonSemanticDebugHandler::emitOpConstantI32(
533 return findOrEmitConstant(SPIRV::OpConstantI, I32TypeReg,
Value,
537MCRegister SPIRVNonSemanticDebugHandler::emitExtInst(
538 SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
555MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeVoidReg(
557 if (!CachedOpTypeVoidReg.isValid())
558 CachedOpTypeVoidReg = findOrEmitOpTypeVoid(MAI);
559 return CachedOpTypeVoidReg;
562MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeInt32Reg(
564 if (!CachedOpTypeInt32Reg.isValid())
565 CachedOpTypeInt32Reg = findOrEmitOpTypeInt32(MAI);
566 return CachedOpTypeInt32Reg;
569MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeVoid(
572 if (
MI->getOpcode() == SPIRV::OpTypeVoid)
589 unsigned Width =
BT->getSizeInBits();
593MCRegister SPIRVNonSemanticDebugHandler::findOrEmitScalarType(
596 bool IsFloat =
BT->getEncoding() == dwarf::DW_ATE_float;
597 unsigned Opcode = IsBool ? SPIRV::OpTypeBool
598 : IsFloat ? SPIRV::OpTypeFloat
602 int64_t Width = IsBool ? 0 :
BT->getSizeInBits();
607 if (Opcode == SPIRV::OpTypeInt && Width == 32)
608 return getOrEmitOpTypeInt32Reg(MAI);
611 ScalarTypeCache.try_emplace({Opcode, Width}, MCRegister());
613 return CacheIt->second;
618 if (
MI->getOpcode() != Opcode)
620 if (IsBool || (
MI->getOperand(1).getImm() == Width &&
621 (IsFloat ||
MI->getOperand(2).getImm() == 0))) {
624 return CacheIt->second;
646 CacheIt->second =
Reg;
653 unsigned Words = IsWide ? 2 : 1;
654 if (
MI.getNumOperands() < 2 + Words)
657 for (
unsigned I = 0;
I < Words; ++
I) {
658 if (!
MI.getOperand(2 +
I).isImm())
664 return Found ==
Value;
667MCRegister SPIRVNonSemanticDebugHandler::findModuleConstant(
671 if (
MI->getOpcode() != Opcode ||
MI->getNumOperands() < 2)
685MCRegister SPIRVNonSemanticDebugHandler::findOrEmitConstant(
688 bool IsBool = Width == 0;
689 bool IsWide = Width == 64;
692 ScalarConstantCache.try_emplace({TypeReg.
id(),
Value}, MCRegister());
694 return CacheIt->second;
697 findModuleConstant(Opcode, TypeReg,
Value, IsBool, IsWide, MAI);
699 CacheIt->second = Found;
715 }
else if (Width == 16) {
722 CacheIt->second =
Reg;
726MCRegister SPIRVNonSemanticDebugHandler::findOrEmitScalarConstant(
728 MCRegister TypeReg = findOrEmitScalarType(
BT, MAI);
733 bool IsFloat =
BT->getEncoding() == dwarf::DW_ATE_float;
735 IsBool ? (
Value ? SPIRV::OpConstantTrue : SPIRV::OpConstantFalse)
736 : IsFloat ?
SPIRV::OpConstantF
737 :
SPIRV::OpConstantI;
738 return findOrEmitConstant(Opcode, TypeReg,
Value,
739 IsBool ? 0 :
BT->getSizeInBits(), MAI);
742MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeInt32(
745 if (
MI->getOpcode() == SPIRV::OpTypeInt &&
746 MI->getOperand(1).getImm() == 32 &&
MI->getOperand(2).getImm() == 0)
762auto SPIRVNonSemanticDebugHandler::getOrCreateDebugScope(
const DIScope *S)
763 -> EmitResult<MCRegister> {
764 if (!S || FailedScopes.contains(S))
765 return EmitResult<MCRegister>::unsupported();
766 if (
auto Reg = lookupOptReg(DebugScopeRegs, S))
767 return EmitResult<MCRegister>::emitted(*
Reg);
771 if (!ScopesInProgress.insert(S).second)
772 return EmitResult<MCRegister>::inProgress();
774 EmitResult<PreparedScope>
P = emitDebugScope(S);
775 ScopesInProgress.erase(S);
776 assert((!
P || !GlobalNSDIEnabled) &&
777 "debug type or scope created after module-scope NSDI emission");
779 if (
P.Status == EmitStatus::Unsupported)
780 FailedScopes.insert(S);
781 return P.Status == EmitStatus::InProgress
782 ? EmitResult<MCRegister>::inProgress()
789 emitExtInst(
P.Value->Opcode, getOrEmitOpTypeVoidReg(MAI),
791 DebugScopeRegs[S] =
Reg;
792 return EmitResult<MCRegister>::emitted(
Reg);
795auto SPIRVNonSemanticDebugHandler::emitDebugTypeBasic(
799 return EmitResult<PreparedScope>::unsupported();
801 MCRegister NameReg = getCachedOpStringReg(
BT->getName());
803 static_cast<uint32_t
>(
BT->getSizeInBits()), I32TypeReg, MAI);
807 unsigned Encoding = 0;
808 switch (
BT->getEncoding()) {
809 case dwarf::DW_ATE_address:
812 case dwarf::DW_ATE_boolean:
815 case dwarf::DW_ATE_float:
818 case dwarf::DW_ATE_signed:
821 case dwarf::DW_ATE_signed_char:
824 case dwarf::DW_ATE_unsigned:
827 case dwarf::DW_ATE_unsigned_char:
831 MCRegister EncodingReg = emitOpConstantI32(Encoding, I32TypeReg, MAI);
832 MCRegister FlagsReg = emitOpConstantI32(0, I32TypeReg, MAI);
833 return EmitResult<PreparedScope>::emitted(
834 PreparedScope{SPIRV::NonSemanticExtInst::DebugTypeBasic,
835 {NameReg, SizeReg, EncodingReg, FlagsReg}});
838auto SPIRVNonSemanticDebugHandler::emitDebugScope(
const DIScope *S)
839 -> EmitResult<PreparedScope> {
840 assert(CurrentMAI &&
"emitDebugScope requires CurrentMAI");
843 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
844 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
847 return emitDebugTypeBasic(
BT, I32TypeReg, MAI);
849 return emitDebugTypeFunctionForSubroutineType(ST, MAI);
851 return emitDebugTypeForCompositeType(CT, VoidTypeReg, I32TypeReg,
854 return emitDebugTypeForDerivedType(DT, VoidTypeReg, I32TypeReg,
857 return emitDebugLexicalBlock(S, VoidTypeReg, I32TypeReg, ExtInstSetReg,
860 if (
SP->isDefinition())
861 return emitDebugFunction(SP, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
862 return emitDebugFunctionDeclaration(SP, VoidTypeReg, I32TypeReg,
865 return EmitResult<PreparedScope>::unsupported();
868auto SPIRVNonSemanticDebugHandler::emitDebugTypeForCompositeType(
871 -> EmitResult<PreparedScope> {
872 switch (CT->getTag()) {
873 case dwarf::DW_TAG_array_type:
886 return emitDebugTypeVector(CT, MAI);
887 return emitDebugTypeArray(CT, MAI);
888 case dwarf::DW_TAG_structure_type:
889 case dwarf::DW_TAG_class_type:
890 case dwarf::DW_TAG_union_type:
891 return emitDebugTypeComposite(CT, VoidTypeReg, I32TypeReg, ExtInstSetReg,
894 return EmitResult<PreparedScope>::unsupported();
898auto SPIRVNonSemanticDebugHandler::emitDebugTypeForDerivedType(
901 -> EmitResult<PreparedScope> {
902 switch (DT->getTag()) {
903 case dwarf::DW_TAG_pointer_type:
904 return emitDebugTypePointer(DT, MAI);
905 case dwarf::DW_TAG_typedef:
906 return emitDebugTypedef(DT, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
907 case dwarf::DW_TAG_member:
908 return emitDebugTypeMember(DT, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
910 return EmitResult<PreparedScope>::unsupported();
914auto SPIRVNonSemanticDebugHandler::emitDebugTypePointer(
916 -> EmitResult<PreparedScope> {
919 if (!PT->getDWARFAddressSpace().has_value())
920 return EmitResult<PreparedScope>::unsupported();
923 if (
const DIType *BaseTy = PT->getBaseType()) {
924 EmitResult<MCRegister>
Base = getOrCreateDebugScope(BaseTy);
926 return EmitResult<PreparedScope>::failure(
Base);
933 BaseReg = CachedDebugInfoNoneReg;
936 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
938 emitOpConstantI32(transDebugFlags(PT), I32TypeReg, MAI);
943 MCRegister StorageClassReg = emitOpConstantI32(
947 return EmitResult<PreparedScope>::emitted(
948 PreparedScope{SPIRV::NonSemanticExtInst::DebugTypePointer,
949 {
BaseReg, StorageClassReg, DebugTypePointerFlagsReg}});
952auto SPIRVNonSemanticDebugHandler::emitDebugTypeFunctionForSubroutineType(
954 -> EmitResult<PreparedScope> {
955 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
956 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
958 emitOpConstantI32(transDebugFlags(ST), I32TypeReg, MAI);
959 DITypeArray
TA =
ST->getTypeArray();
966 Ops.push_back(VoidTypeReg);
968 for (
unsigned I = 0,
E =
TA.size();
I !=
E; ++
I) {
969 bool IsReturnType = (
I == 0);
970 EmitResult<MCRegister>
Slot =
971 mapDISignatureTypeToReg(TA[
I], VoidTypeReg, IsReturnType);
975 return EmitResult<PreparedScope>::failure(Slot);
979 return EmitResult<PreparedScope>::emitted(
980 PreparedScope{SPIRV::NonSemanticExtInst::DebugTypeFunction,
Ops});
984SPIRVNonSemanticDebugHandler::EmitResult<MCRegister>
985SPIRVNonSemanticDebugHandler::resolveScope(
const DIScope *Scope,
989 Scope = DLBF->getScope();
992 return getOrCreateDebugScope(Scope);
995 auto CUResult = [](std::optional<MCRegister>
Reg) {
996 return Reg ? EmitResult<MCRegister>::emitted(*
Reg)
1000 return CUResult(lookupOptReg(DebugScopeRegs, FallbackCU));
1002 if (CompileUnits.empty())
1003 return EmitResult<MCRegister>::unsupported();
1005 return CUResult(lookupOptReg(DebugScopeRegs, CompileUnits[0].TheCU));
1008auto SPIRVNonSemanticDebugHandler::emitDebugLexicalBlock(
1011 -> EmitResult<PreparedScope> {
1013 "S must be a DILexicalBlock or DINamespace in emitDebugLexicalBlock");
1014 EmitResult<MCRegister> Parent =
resolveScope(S->getScope());
1016 return EmitResult<PreparedScope>::failure(Parent);
1018 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1019 S->getFile(),
true);
1020 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1021 ExtInstSetReg, MAI);
1025 MCRegister LineReg = emitOpConstantI32(
static_cast<uint32_t
>(LB->getLine()),
1028 static_cast<uint32_t
>(LB->getColumn()), I32TypeReg, MAI);
1029 Ops = {SrcReg, LineReg, ColReg, *Parent.Value};
1033 MCRegister LineReg = emitOpConstantI32(0, I32TypeReg, MAI);
1034 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
1035 MCRegister NameReg = getCachedOpStringReg(NS->getName());
1036 Ops = {SrcReg, LineReg, ColReg, *Parent.Value, NameReg};
1039 return EmitResult<PreparedScope>::emitted(
1040 PreparedScope{SPIRV::NonSemanticExtInst::DebugLexicalBlock,
Ops});
1043MCRegister SPIRVNonSemanticDebugHandler::getOrEmitDebugInlinedAt(
1046 assert(IA &&
"IA must not be null in getOrEmitDebugInlinedAt");
1048 if (MCRegister Cached = DebugInlinedAtRegs.lookup(IA))
1051 EmitResult<MCRegister>
Scope = resolveScope(
IA->getScope());
1053 return MCRegister();
1055 MCRegister LineReg =
1056 emitOpConstantI32(
static_cast<uint32_t
>(
IA->getLine()), I32TypeReg, MAI);
1061 if (
const DILocation *Outer =
IA->getInlinedAt()) {
1062 MCRegister OuterReg = getOrEmitDebugInlinedAt(
1063 Outer, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
1065 return MCRegister();
1066 Ops.push_back(OuterReg);
1069 MCRegister
Reg = emitExtInst(SPIRV::NonSemanticExtInst::DebugInlinedAt,
1070 VoidTypeReg, ExtInstSetReg,
Ops, MAI);
1071 DebugInlinedAtRegs[
IA] =
Reg;
1075auto SPIRVNonSemanticDebugHandler::emitDebugFunctionDeclaration(
1078 -> EmitResult<PreparedScope> {
1079 assert(SP &&
"SP must not be null in emitDebugFunctionDeclaration");
1081 "SP must not be a definition in emitDebugFunctionDeclaration");
1084 EmitResult<MCRegister> FnTy = getOrCreateDebugScope(
SP->getType());
1086 return EmitResult<PreparedScope>::failure(FnTy);
1088 EmitResult<MCRegister> Parent =
resolveScope(
SP->getScope(),
SP->getUnit());
1090 return EmitResult<PreparedScope>::failure(Parent);
1092 MCRegister FileStrReg = getCachedScopePathOpStringReg(SP);
1094 MCRegister NameReg = getCachedOpStringReg(
SP->getName());
1095 MCRegister LinkageReg = getCachedOpStringReg(
SP->getLinkageName());
1096 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1097 ExtInstSetReg, MAI);
1100 emitOpConstantI32(
static_cast<uint32_t
>(
SP->getLine()), I32TypeReg, MAI);
1101 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
1103 uint32_t FlagsVal = transDebugFlags(SP);
1106 FlagsVal &= ~NSDIFlagIsDefinition;
1107 MCRegister FlagsReg = emitOpConstantI32(FlagsVal, I32TypeReg, MAI);
1109 return EmitResult<PreparedScope>::emitted(
1110 PreparedScope{SPIRV::NonSemanticExtInst::DebugFunctionDeclaration,
1111 {NameReg, *FnTy.Value, SrcReg, LineReg, ColReg,
1112 *Parent.Value, LinkageReg, FlagsReg}});
1115auto SPIRVNonSemanticDebugHandler::emitDebugFunction(
1118 -> EmitResult<PreparedScope> {
1119 assert(SP &&
"SP must not be null in emitDebugFunction");
1120 assert(
SP->isDefinition() &&
"SP must be a definition in emitDebugFunction");
1122 EmitResult<MCRegister> FnTy = getOrCreateDebugScope(
SP->getType());
1124 return EmitResult<PreparedScope>::failure(FnTy);
1126 EmitResult<MCRegister> Parent =
resolveScope(
SP->getScope(),
SP->getUnit());
1128 return EmitResult<PreparedScope>::failure(Parent);
1130 MCRegister NameReg = getCachedOpStringReg(
SP->getName());
1131 MCRegister LinkageReg = getCachedOpStringReg(
SP->getLinkageName());
1132 MCRegister FileStrReg = getCachedScopePathOpStringReg(SP);
1133 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1134 ExtInstSetReg, MAI);
1137 emitOpConstantI32(
static_cast<uint32_t
>(
SP->getLine()), I32TypeReg, MAI);
1140 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
1141 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(SP), I32TypeReg, MAI);
1143 static_cast<uint32_t
>(
SP->getScopeLine()), I32TypeReg, MAI);
1146 LineReg, ColReg, *Parent.Value,
1147 LinkageReg, FlagsReg, ScopeLineReg};
1150 EmitResult<MCRegister> DeclRes = getOrCreateDebugScope(Decl);
1152 Ops.push_back(*DeclRes.Value);
1155 return EmitResult<PreparedScope>::emitted(
1156 PreparedScope{SPIRV::NonSemanticExtInst::DebugFunction,
Ops});
1159auto SPIRVNonSemanticDebugHandler::mapDISignatureTypeToReg(
1161 -> EmitResult<MCRegister> {
1164 return EmitResult<MCRegister>::emitted(VoidTypeReg);
1165 assert(CachedDebugInfoNoneReg.isValid() &&
1166 "DebugInfoNone must be emitted before DISubroutineType operands");
1167 return EmitResult<MCRegister>::emitted(CachedDebugInfoNoneReg);
1169 return getOrCreateDebugScope(Ty);
1187static std::optional<NonSemanticDebugOp>
1190 case dwarf::DW_OP_deref:
1192 case dwarf::DW_OP_plus:
1194 case dwarf::DW_OP_minus:
1196 case dwarf::DW_OP_plus_uconst:
1198 case dwarf::DW_OP_bit_piece:
1200 case dwarf::DW_OP_swap:
1202 case dwarf::DW_OP_xderef:
1204 case dwarf::DW_OP_stack_value:
1206 case dwarf::DW_OP_constu:
1211 return std::nullopt;
1217static std::optional<SmallVector<uint32_t, 3>>
1219 std::optional<NonSemanticDebugOp> NSOp =
1222 return std::nullopt;
1225 for (
unsigned I = 0,
E =
Op.getNumArgs();
I !=
E; ++
I) {
1228 return std::nullopt;
1234std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugOperation(
1240 return std::nullopt;
1242 auto [It,
Inserted] = DebugOperationCache.try_emplace(std::move(*
Key));
1247 for (uint32_t V : It->first)
1248 Operands.push_back(emitOpConstantI32(V, I32TypeReg, MAI));
1249 MCRegister
Reg = emitExtInst(SPIRV::NonSemanticExtInst::DebugOperation,
1250 VoidTypeReg, ExtInstSetReg,
Operands, MAI);
1255std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugExpression(
1258 assert(Expr &&
"Expr must not be null in emitDebugExpression");
1261 for (
const DIExpression::ExprOperand &
Op : Expr->
expr_ops()) {
1262 std::optional<MCRegister> OpReg =
1263 emitDebugOperation(
Op, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
1265 return std::nullopt;
1270 DebugExpressionCache.try_emplace(std::move(OperationRegs));
1274 MCRegister
Reg = emitExtInst(SPIRV::NonSemanticExtInst::DebugExpression,
1275 VoidTypeReg, ExtInstSetReg, It->first, MAI);
1280std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugGlobalVariable(
1284 assert(GV &&
"GV must not be null in emitDebugGlobalVariable");
1286 EmitResult<MCRegister> Parent = resolveScope(GV->
getScope());
1288 return std::nullopt;
1290 MCRegister ParentReg = *Parent.Value;
1296 MCRegister TyReg = CachedDebugInfoNoneReg;
1297 if (
const DIType *Ty = GV->
getType()) {
1298 auto TyRegOpt = lookupOptReg(DebugScopeRegs, Ty);
1300 return std::nullopt;
1304 std::optional<MCRegister> StaticMemberRegOpt;
1307 StaticMemberRegOpt = lookupOptReg(DebugScopeRegs, SM);
1308 if (!StaticMemberRegOpt)
1309 return std::nullopt;
1312 MCRegister NameReg = getCachedOpStringReg(GV->
getName());
1313 MCRegister LinkageReg = getCachedOpStringReg(GV->
getLinkageName());
1314 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1316 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1317 ExtInstSetReg, MAI);
1319 MCRegister LineReg =
1320 emitOpConstantI32(
static_cast<uint32_t
>(GV->
getLine()), I32TypeReg, MAI);
1324 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
1331 MCRegister VariableReg = CachedDebugInfoNoneReg;
1332 if (
const GlobalVariable *LLVMGV =
Info.LLVMGV) {
1335 VariableReg = GVReg;
1336 }
else if (
Info.Expr &&
Info.Expr->getNumElements() != 0) {
1337 if (
auto ExprReg = emitDebugExpression(
Info.Expr, VoidTypeReg, I32TypeReg,
1338 ExtInstSetReg, MAI))
1339 VariableReg = *ExprReg;
1342 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(GV), I32TypeReg, MAI);
1345 LineReg, ColReg, ParentReg,
1346 LinkageReg, VariableReg, FlagsReg};
1348 if (StaticMemberRegOpt)
1349 Ops.push_back(*StaticMemberRegOpt);
1351 return emitExtInst(SPIRV::NonSemanticExtInst::DebugGlobalVariable,
1352 VoidTypeReg, ExtInstSetReg,
Ops, MAI);
1355std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugLocalVariable(
1358 assert(LV &&
"LV must not be null in emitDebugLocalVariable");
1360 EmitResult<MCRegister> Parent = resolveScope(LV->
getScope());
1362 return std::nullopt;
1364 MCRegister TyReg = CachedDebugInfoNoneReg;
1365 if (
const DIType *Ty = LV->
getType()) {
1366 auto TyRegOpt = lookupOptReg(DebugScopeRegs, Ty);
1368 return std::nullopt;
1372 MCRegister NameReg = getCachedOpStringReg(LV->
getName());
1373 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1375 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1376 ExtInstSetReg, MAI);
1377 MCRegister LineReg =
1378 emitOpConstantI32(
static_cast<uint32_t
>(LV->
getLine()), I32TypeReg, MAI);
1380 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
1381 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(LV), I32TypeReg, MAI);
1384 ColReg, *Parent.Value, FlagsReg};
1385 if (
unsigned Arg = LV->
getArg())
1386 Ops.push_back(emitOpConstantI32(Arg, I32TypeReg, MAI));
1388 return emitExtInst(SPIRV::NonSemanticExtInst::DebugLocalVariable, VoidTypeReg,
1389 ExtInstSetReg,
Ops, MAI);
1392auto SPIRVNonSemanticDebugHandler::emitDebugTypeVector(
1394 -> EmitResult<PreparedScope> {
1397 return EmitResult<PreparedScope>::unsupported();
1401 DINodeArray
Elements = VT->getElements();
1403 return EmitResult<PreparedScope>::unsupported();
1407 return EmitResult<PreparedScope>::unsupported();
1409 EmitResult<MCRegister>
Base = getOrCreateDebugScope(BaseTy);
1411 return EmitResult<PreparedScope>::failure(
Base);
1413 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
1415 static_cast<uint32_t
>(CI->getZExtValue()), I32TypeReg, MAI);
1416 return EmitResult<PreparedScope>::emitted(PreparedScope{
1417 SPIRV::NonSemanticExtInst::DebugTypeVector, {*
Base.Value, CountReg}});
1420auto SPIRVNonSemanticDebugHandler::emitDebugTypeArray(
1422 -> EmitResult<PreparedScope> {
1425 EmitResult<MCRegister>
Base = getOrCreateDebugScope(AT->getBaseType());
1427 return EmitResult<PreparedScope>::failure(
Base);
1429 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
1437 for (
const DINode *Element : AT->getElements()) {
1449 if (
Value.getActiveBits() <= 32)
1450 Count =
static_cast<uint32_t
>(
Value.getZExtValue());
1452 Ops.push_back(emitOpConstantI32(
Count, I32TypeReg, MAI));
1455 return EmitResult<PreparedScope>::emitted(
1456 PreparedScope{SPIRV::NonSemanticExtInst::DebugTypeArray,
Ops});
1459auto SPIRVNonSemanticDebugHandler::emitDebugTypeMember(
1462 -> EmitResult<PreparedScope> {
1463 EmitResult<MCRegister> Ty = getOrCreateDebugScope(
M->getBaseType());
1465 return EmitResult<PreparedScope>::failure(Ty);
1468 return EmitResult<PreparedScope>::unsupported();
1470 MCRegister NameReg = getCachedOpStringReg(
M->getName());
1471 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1472 M->getFile(),
true);
1473 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1474 ExtInstSetReg, MAI);
1476 emitOpConstantI32(
static_cast<uint32_t
>(
M->getLine()), I32TypeReg, MAI);
1479 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
1481 static_cast<uint32_t
>(
M->getOffsetInBits()), I32TypeReg, MAI);
1483 static_cast<uint32_t
>(
M->getSizeInBits()), I32TypeReg, MAI);
1484 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(M), I32TypeReg, MAI);
1495 return EmitResult<PreparedScope>::emitted(
1496 PreparedScope{SPIRV::NonSemanticExtInst::DebugTypeMember,
1497 {NameReg, *Ty.Value, SrcReg, LineReg, ColReg, OffsetReg,
1498 SizeReg, FlagsReg}});
1501auto SPIRVNonSemanticDebugHandler::emitDebugTypeComposite(
1504 -> EmitResult<PreparedScope> {
1507 EmitResult<MCRegister> Parent =
resolveScope(CT->getScope());
1509 return EmitResult<PreparedScope>::failure(Parent);
1512 return EmitResult<PreparedScope>::unsupported();
1515 for (
const DINode *Element : CT->getElements()) {
1517 if (!M ||
M->getTag() != dwarf::DW_TAG_member)
1519 EmitResult<MCRegister>
Member = getOrCreateDebugScope(M);
1524 MCRegister NameReg = getCachedOpStringReg(CT->getName());
1525 MCRegister LinkageReg = getCachedOpStringReg(CT->getIdentifier());
1526 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1527 CT->getFile(),
true);
1528 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1529 ExtInstSetReg, MAI);
1532 emitOpConstantI32(mapCompositeTypeTag(CT->getTag()), I32TypeReg, MAI);
1534 emitOpConstantI32(
static_cast<uint32_t
>(CT->getLine()), I32TypeReg, MAI);
1535 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
1539 if (!CT->isForwardDecl())
1540 SizeReg = emitOpConstantI32(
static_cast<uint32_t
>(CT->getSizeInBits()),
1543 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(CT), I32TypeReg, MAI);
1546 LineReg, ColReg, *Parent.Value,
1547 LinkageReg, SizeReg, FlagsReg};
1549 return EmitResult<PreparedScope>::emitted(
1550 PreparedScope{SPIRV::NonSemanticExtInst::DebugTypeComposite,
Ops});
1553auto SPIRVNonSemanticDebugHandler::emitDebugTypedef(
1556 -> EmitResult<PreparedScope> {
1557 EmitResult<MCRegister>
Base = getOrCreateDebugScope(TD->getBaseType());
1559 return EmitResult<PreparedScope>::failure(
Base);
1561 MCRegister NameReg = getCachedOpStringReg(TD->getName());
1562 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1563 TD->getFile(),
true);
1564 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1565 ExtInstSetReg, MAI);
1567 emitOpConstantI32(
static_cast<uint32_t
>(TD->getLine()), I32TypeReg, MAI);
1569 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
1574 EmitResult<MCRegister> Parent =
resolveScope(TD->getScope());
1576 return EmitResult<PreparedScope>::failure(Parent);
1578 return EmitResult<PreparedScope>::emitted(PreparedScope{
1579 SPIRV::NonSemanticExtInst::DebugTypedef,
1580 {NameReg, *
Base.Value, SrcReg, LineReg, ColReg, *Parent.Value}});
1585 if (CompileUnits.empty())
1593 for (
const CompileUnitInfo &Info : CompileUnits) {
1595 MCRegister PathReg = emitOpStringIfNew(Info.FilePath, MAI);
1596 ScopeToPathOpStringReg[Info.TheCU] = PathReg;
1597 if (
const DIFile *
F = Info.TheCU->getFile())
1598 ScopeToPathOpStringReg[
F] = PathReg;
1603 emitOpStringIfNew(SP->getName(), MAI);
1604 emitOpStringIfNew(SP->getLinkageName(), MAI);
1605 emitAndCacheScopePathOpStringReg(SP, MAI);
1608 for (
const DIType *Ty : DebugTypes) {
1610 emitOpStringIfNew(
BT->getName(), MAI);
1617 if (CT->getTag() != dwarf::DW_TAG_structure_type &&
1618 CT->getTag() != dwarf::DW_TAG_class_type &&
1619 CT->getTag() != dwarf::DW_TAG_union_type)
1621 emitOpStringIfNew(CT->getName(), MAI);
1622 emitOpStringIfNew(CT->getIdentifier(), MAI);
1623 emitAndCacheScopePathOpStringReg(CT->getFile(), MAI);
1624 for (
const DINode *Element : CT->getElements()) {
1626 if (!M || M->getTag() != dwarf::DW_TAG_member)
1628 emitOpStringIfNew(M->getName(), MAI);
1629 emitAndCacheScopePathOpStringReg(M->getFile(), MAI);
1635 if (TD && TD->getTag() == dwarf::DW_TAG_typedef) {
1636 emitOpStringIfNew(TD->getName(), MAI);
1637 emitAndCacheScopePathOpStringReg(TD->getFile(), MAI);
1641 for (
const auto &[GV,
_] : GlobalVariableDebugInfoMap) {
1642 emitOpStringIfNew(GV->
getName(), MAI);
1644 emitAndCacheScopePathOpStringReg(GV->
getFile(), MAI);
1648 emitOpStringIfNew(LV->
getName(), MAI);
1649 emitAndCacheScopePathOpStringReg(LV->
getFile(), MAI);
1654 for (
const DIScope *S : LexicalBlocks) {
1655 emitAndCacheScopePathOpStringReg(S->getFile(), MAI);
1657 emitOpStringIfNew(NS->getName(), MAI);
1661 emitAndCacheScopePathOpStringReg(
DL->getScope(), MAI);
1663 CachedEmptyStringReg = emitOpStringIfNew(
"", MAI);
1666 NonSemanticOpStringsSectionEmitted =
true;
1670void SPIRVNonSemanticDebugHandler::emitDebugFunctionDefinition(
1674 "DebugFunctionDefinition operands must be valid");
1675 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
1677 emitExtInst(SPIRV::NonSemanticExtInst::DebugFunctionDefinition, VoidTypeReg,
1678 ExtInstSetReg, {DebugFunctionReg, OpFunctionReg}, MAI);
1681void SPIRVNonSemanticDebugHandler::resetPerFunctionDebugState() {
1682 CurrentMF =
nullptr;
1683 LastFunctionOpVariable =
nullptr;
1684 DebugFunctionDefinitionEmitted =
false;
1685 LastLineMI =
nullptr;
1686 LastScopeMI =
nullptr;
1690void SPIRVNonSemanticDebugHandler::preparePerFunctionDebug(
1692 resetPerFunctionDebugState();
1693 if (!GlobalNSDIEnabled || !CurrentMAI)
1704 if (!SP || !
SP->isDefinition())
1709 LastFunctionOpVariable =
1710 findLastFunctionOpVariableDeclaration(*MF, *CurrentMAI);
1712 analyzeDebugRecords(*MF);
1715void SPIRVNonSemanticDebugHandler::tryEmitDebugFunctionDefinition(
1717 if (DebugFunctionDefinitionEmitted || !GlobalNSDIEnabled)
1720 assert(CurrentMF &&
"no current MachineFunction");
1721 const Function &
F = CurrentMF->getFunction();
1722 const DISubprogram *
SP =
F.getSubprogram();
1723 if (!SP || !
SP->isDefinition())
1726 auto DFIt = DebugScopeRegs.find(SP);
1727 if (DFIt == DebugScopeRegs.end())
1734 emitDebugFunctionDefinition(DFIt->second, OpFunctionReg, MAI);
1735 DebugFunctionDefinitionEmitted =
true;
1740 preparePerFunctionDebug(MF);
1745 resetPerFunctionDebugState();
1752 if (!DebugFunctionDefinitionEmitted)
1755 emitAnalyzedRecords(
MI);
1757 std::optional<const MachineInstr *>
Target = resolveDebugLocTarget(
MI);
1761 (void)emitDebugScopeForInstruction(*
Target);
1762 emitDebugLineForInstruction(*
Target);
1772static std::optional<Register>
1776 if (!
MI.isIndirectDebugValue())
1777 return std::nullopt;
1781 Register LocReg =
MI.getDebugOperand(0).getReg();
1783 return std::nullopt;
1794 const MachineInstr *Def =
MI.getMF()->getRegInfo().getUniqueVRegDef(LocReg);
1795 if (!Def || Def->getOpcode() != SPIRV::OpVariable)
1796 return std::nullopt;
1801void SPIRVNonSemanticDebugHandler::emitDebugBinding(
1802 SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
1804 assert(DebugFunctionDefinitionEmitted &&
1805 "DebugFunctionDefinition must be emitted");
1806 assert(CurrentMAI &&
"CurrentMAI must be set");
1808 auto VarRegOpt = lookupOptReg(DebugLocalVariableRegs,
MI->getDebugVariable());
1812 auto ExprRegOpt = lookupOptReg(DebugExpressionRegs,
MI->getDebugExpression());
1816 if (!emitDebugScopeForInstruction(
MI))
1818 emitDebugLineForInstruction(
MI);
1820 SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI;
1821 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
1823 emitExtInst(Opcode, VoidTypeReg, ExtInstSetReg,
1824 {*VarRegOpt, LocationReg, *ExprRegOpt}, MAI);
1829static std::optional<std::pair<const DIBasicType *, uint64_t>>
1831 if (!
MI.isNonListDebugValue() ||
MI.isIndirectDebugValue())
1832 return std::nullopt;
1836 return std::nullopt;
1841 return std::nullopt;
1846 else if (
Value.isCImm())
1850 return std::make_pair(
BT, Bits);
1853std::optional<MCRegister> SPIRVNonSemanticDebugHandler::getConstantValueReg(
1855 std::optional<std::pair<const DIBasicType *, uint64_t>>
Const =
1858 return std::nullopt;
1860 auto It = ConstantValueRegs.find(*Const);
1861 if (It == ConstantValueRegs.end() || !It->second.isValid())
1862 return std::nullopt;
1867 if (!
MI.isNonListDebugValue() ||
MI.isIndirectDebugValue())
1868 return std::nullopt;
1872 return std::nullopt;
1876 return std::nullopt;
1878 const MachineInstr *Def =
MI.getMF()->getRegInfo().getUniqueVRegDef(ValueReg);
1879 if (!Def || (Def->isPseudo() && !Def->isPHI()) || Def->isMetaInstruction() ||
1880 Def->getNumOperands() == 0 || !Def->getOperand(0).isReg() ||
1881 !Def->getOperand(0).isDef() || Def->getOperand(0).getReg() != ValueReg)
1882 return std::nullopt;
1888 return Opcode == SPIRV::OpSelectionMerge || Opcode == SPIRV::OpLoopMerge ||
1889 Opcode == SPIRV::OpLoopControlINTEL;
1901 switch (
MI->getOpcode()) {
1902 case SPIRV::OpFunction:
1903 case SPIRV::OpFunctionParameter:
1904 case SPIRV::OpFunctionEnd:
1905 case SPIRV::OpLabel:
1906 case TargetOpcode::PHI:
1917 :
MI->getPrevNode();
1918 Adj; Adj = Forward ? Adj->getNextNode() : Adj->getPrevNode()) {
1926std::optional<const MachineInstr *>
1927SPIRVNonSemanticDebugHandler::resolveDebugLocTarget(
const MachineInstr *
MI) {
1928 assert(CurrentMAI &&
"CurrentMAI must be set");
1929 SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI;
1934 return std::nullopt;
1942 return std::nullopt;
1948 assert(
MI &&
"Merge instruction must be followed by a terminator");
1952 return std::nullopt;
1958void SPIRVNonSemanticDebugHandler::resolveDebugRecord(
1961 SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI;
1967 const MachineInstr *Anchor =
1977 placeRecord(SPIRV::NonSemanticExtInst::DebugDeclare,
MI, StorageReg,
1982 if (std::optional<MCRegister> ConstReg = getConstantValueReg(
MI)) {
1983 placeRecord(SPIRV::NonSemanticExtInst::DebugValue,
MI, *ConstReg, Anchor);
2003 if (ModuleScopeIds.contains(ValueReg) ||
2005 placeRecord(SPIRV::NonSemanticExtInst::DebugValue,
MI, ValueReg, Anchor);
2008void SPIRVNonSemanticDebugHandler::analyzeDebugRecords(
2010 assert(CurrentMAI &&
"CurrentMAI must be set");
2014 std::optional<MachineDominatorTree> DomTree;
2016 for (
const MachineBasicBlock &
MBB : MF) {
2017 const MachineInstr *LastEmitted =
nullptr;
2018 for (
const MachineInstr &
MI :
MBB) {
2019 if (
MI.isDebugValueLike()) {
2022 resolveDebugRecord(
MI, LastEmitted, *DomTree);
2031void SPIRVNonSemanticDebugHandler::placeRecord(
2032 SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
2035 Records[Anchor].push_back({&
MI, Opcode, LocationReg});
2038void SPIRVNonSemanticDebugHandler::emitAnalyzedRecords(
2040 auto It = Records.find(Anchor);
2041 if (It == Records.end())
2043 for (
const DebugRecord &R : It->second)
2044 emitDebugBinding(
R.Opcode,
R.MI,
R.LocationReg);
2047bool SPIRVNonSemanticDebugHandler::emitDebugScopeForInstruction(
2049 assert(DebugFunctionDefinitionEmitted &&
2050 "DebugFunctionDefinition must be emitted");
2051 assert(CurrentMAI &&
"CurrentMAI must be set");
2056 if (LastScopeMI &&
MI->getParent() != LastScopeMI->getParent())
2057 LastScopeMI =
nullptr;
2059 SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI;
2060 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
2063 const DILocation *CurDL =
MI->getDebugLoc().get();
2068 emitExtInst(SPIRV::NonSemanticExtInst::DebugNoScope, VoidTypeReg,
2069 ExtInstSetReg, {}, MAI);
2070 LastScopeMI =
nullptr;
2075 const DIScope *CurScope = CurDL->getScope();
2076 const DILocation *CurInlinedAt = CurDL->getInlinedAt();
2079 const DILocation *LastDL = LastScopeMI->getDebugLoc().get();
2080 if (LastDL->getScope() == CurScope &&
2081 LastDL->getInlinedAt() == CurInlinedAt)
2085 EmitResult<MCRegister> CurScopeRes = resolveScope(CurScope);
2092 MCRegister InlinedReg = DebugInlinedAtRegs.lookup(CurInlinedAt);
2095 Ops.push_back(InlinedReg);
2099 emitExtInst(SPIRV::NonSemanticExtInst::DebugScope, VoidTypeReg, ExtInstSetReg,
2106void SPIRVNonSemanticDebugHandler::emitDebugLineForInstruction(
2108 assert(DebugFunctionDefinitionEmitted &&
2109 "DebugFunctionDefinition must be emitted");
2110 assert(CurrentMAI &&
"CurrentMAI must be set");
2115 if (LastLineMI &&
MI->getParent() != LastLineMI->getParent())
2116 LastLineMI =
nullptr;
2118 SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI;
2119 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
2122 const DILocation *
DL =
MI->getDebugLoc().get();
2127 emitExtInst(SPIRV::NonSemanticExtInst::DebugNoLine, VoidTypeReg,
2128 ExtInstSetReg, {}, MAI);
2129 LastLineMI =
nullptr;
2139 MCRegister FileStrReg = getCachedScopePathOpStringReg(
2140 DL->getScope(),
true);
2141 unsigned Line =
DL->getLine();
2142 unsigned Col =
DL->getColumn();
2144 unsigned I32TypeId = CachedOpTypeInt32Reg.id();
2145 MCRegister SrcReg = DebugSourceRegByFileStr.lookup(FileStrReg.
id());
2146 MCRegister LineReg = ScalarConstantCache.lookup({I32TypeId,
Line});
2147 MCRegister ColStartReg = ScalarConstantCache.lookup({I32TypeId, Col});
2148 MCRegister ColEndReg = ScalarConstantCache.lookup({I32TypeId, Col + 1});
2160 if (LastLineMI &&
MI->getDebugLoc() == LastLineMI->getDebugLoc())
2164 emitExtInst(SPIRV::NonSemanticExtInst::DebugLine, VoidTypeReg, ExtInstSetReg,
2165 {SrcReg, LineReg, LineReg, ColStartReg, ColEndReg}, MAI);
2174 if (!
MI || !GlobalNSDIEnabled || !CurrentMF)
2177 if (DebugFunctionDefinitionEmitted ||
MI != LastFunctionOpVariable)
2183 assert(CurrentMAI &&
"CurrentMAI must be set");
2184 tryEmitDebugFunctionDefinition(*CurrentMAI);
2189 if (!GlobalNSDIEnabled || DebugFunctionDefinitionEmitted || !CurrentMF)
2192 assert(CurrentMF == &MF &&
2193 "notification does not match the current MachineFunction");
2195 if (LastFunctionOpVariable)
2201 tryEmitDebugFunctionDefinition(*CurrentMAI);
2212 if (
MI.isDebugValueLike())
2217void SPIRVNonSemanticDebugHandler::collectDebugExpressions(
2219 MachineModuleInfo *ModuleInfo =
Asm->MMI;
2220 assert(ModuleInfo &&
"MachineModuleInfo must be set during module output");
2223 Out.insert(
MI.getDebugExpression());
2229 if (GlobalDIEmitted)
2232 GlobalDIEmitted =
true;
2234 if (CompileUnits.empty()) {
2235 GlobalNSDIEnabled =
false;
2241 if (!ExtInstSetReg.
isValid()) {
2242 GlobalNSDIEnabled =
false;
2247 assert(NonSemanticOpStringsSectionEmitted &&
2248 "emitNonSemanticDebugStrings() must run before "
2249 "emitNonSemanticGlobalDebugInfo()");
2254 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
2255 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
2257 CachedDebugInfoNoneReg = emitExtInst(SPIRV::NonSemanticExtInst::DebugInfoNone,
2258 VoidTypeReg, ExtInstSetReg, {}, MAI);
2270 MCRegister DebugInfoVersionReg = emitOpConstantI32(100, I32TypeReg, MAI);
2272 emitOpConstantI32(
static_cast<uint32_t>(DwarfVersion), I32TypeReg, MAI);
2277 map_to_vector(CompileUnits, [&](
const CompileUnitInfo &Info) {
2278 return emitOpConstantI32(Info.SpirvSourceLanguage, I32TypeReg, MAI);
2282 for (
auto [Info, SrcLangReg] :
llvm::zip(CompileUnits, SrcLangRegs)) {
2283 MCRegister FileStrReg = ScopeToPathOpStringReg.lookup(Info.TheCU);
2285 "CU path OpString must be emitted in emitNonSemanticDebugStrings");
2286 MCRegister DebugSourceReg = getOrEmitDebugSourceForFileStrReg(
2287 FileStrReg, VoidTypeReg, ExtInstSetReg, MAI);
2289 SPIRV::NonSemanticExtInst::DebugCompilationUnit, VoidTypeReg,
2291 {DebugInfoVersionReg, DwarfVersionReg, DebugSourceReg, SrcLangReg},
2294 DebugScopeRegs[Info.TheCU] = CUDbgReg;
2299 getOrCreateDebugScope(S);
2304 if (
auto LVReg = emitDebugLocalVariable(LV, VoidTypeReg, I32TypeReg,
2305 ExtInstSetReg, MAI))
2306 DebugLocalVariableRegs[LV] = *LVReg;
2313 collectDebugExpressions(Expressions);
2315 if (
auto ExprReg = emitDebugExpression(Expr, VoidTypeReg, I32TypeReg,
2316 ExtInstSetReg, MAI))
2317 DebugExpressionRegs[Expr] = *ExprReg;
2320 for (
const auto &[GV, Info] : GlobalVariableDebugInfoMap)
2321 emitDebugGlobalVariable(GV, Info, VoidTypeReg, I32TypeReg, ExtInstSetReg,
2327 getOrEmitDebugInlinedAt(IA, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
2332 assert(ModuleInfo &&
"MachineModuleInfo must be set during module output");
2334 std::optional<std::pair<const DIBasicType *, uint64_t>> Const =
2338 if (!DebugLocalVariableRegs.contains(
MI.getDebugVariable()) ||
2339 !DebugExpressionRegs.contains(
MI.getDebugExpression()))
2341 auto [It, Inserted] = ConstantValueRegs.try_emplace(*Const,
MCRegister());
2343 It->second = findOrEmitScalarConstant(Const->first, Const->second, MAI);
2344 if (!It->second.isValid())
2345 ConstantValueRegs.erase(It);
2349 emitOpConstantI32(
DL->getLine(), I32TypeReg, MAI);
2350 emitOpConstantI32(
DL->getColumn(), I32TypeReg, MAI);
2351 emitOpConstantI32(
DL->getColumn() + 1, I32TypeReg, MAI);
2353 getCachedScopePathOpStringReg(
DL->getScope(),
2355 getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg, ExtInstSetReg,
2359 GlobalNSDIEnabled =
true;
2363SPIRVNonSemanticDebugHandler::getDebugFullPath(
const DIScope *Scope)
const {
2373 Out.assign(Dir.
begin(), Dir.
end());
2379MCRegister SPIRVNonSemanticDebugHandler::getOrEmitDebugSourceForFileStrReg(
2382 const unsigned Key = FileStrReg.
id();
2383 auto It = DebugSourceRegByFileStr.find(
Key);
2384 if (It != DebugSourceRegByFileStr.end())
2387 MCRegister
DS = emitExtInst(SPIRV::NonSemanticExtInst::DebugSource,
2388 VoidTypeReg, ExtInstSetReg, {FileStrReg}, MAI);
2389 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 NVPTX::Scope resolveScope(NVPTX::Scope S, const NVPTXSubtarget *T)
static constexpr StringLiteral Filename
static const MachineInstr * findAdjacentEmittedInstruction(const MachineInstr *MI, SPIRV::ModuleAnalysisInfo &MAI, bool Forward)
static std::optional< SmallVector< uint32_t, 3 > > mapExprOperand(const DIExpression::ExprOperand &Op)
static bool scalarTypeNeedsCapability(const DIBasicType *BT)
static bool isBooleanType(const DIBasicType *BT)
static bool constantHasValue(const MachineInstr &MI, uint64_t Value, bool IsWide)
static void collectLexicalBlockChain(const DIScope *S, SetVector< const DIScope * > &Out)
static bool isMergeInstruction(unsigned Opcode)
static std::optional< std::pair< const DIBasicType *, uint64_t > > getConstantDbgValueBits(const MachineInstr &MI)
static void forEachDebugValueLike(const MachineModuleInfo &ModuleInfo, function_ref< void(const MachineInstr &)> Fn)
static MCRegister getResultId(const MachineInstr &MI, SPIRV::ModuleAnalysisInfo &MAI)
static bool isEmitted(const MachineInstr *MI, SPIRV::ModuleAnalysisInfo &MAI)
static std::optional< Register > getDebugValueReg(const MachineInstr &MI)
static bool isDebugLocTarget(const MachineInstr *MI, SPIRV::ModuleAnalysisInfo &MAI)
static uint64_t constantBits(uint64_t Value, const DIBasicType *BT)
static std::optional< Register > getDebugDeclareStorageReg(const MachineInstr &MI)
static std::optional< NonSemanticDebugOp > mapDwarfOpToNonSemanticOp(uint64_t DwarfOp)
static const DIBasicType * stripToScalarType(const DIType *Ty)
static void collectDebugLocationsAndLocalVariables(const Module &M, SetVector< const DILocation * > &Locations, SetVector< const DILocalVariable * > &LVs)
#define SPIRV_BACKEND_SERVICE_FUN_NAME
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
Class for arbitrary precision integers.
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'.
A lightweight wrapper around an expression operand.
iterator_range< expr_op_iterator > expr_ops() const
A pair of DIGlobalVariable and DIExpression.
DIDerivedType * getStaticDataMemberDeclaration() const
StringRef getLinkageName() const
DILocalScope * getScope() const
Get the local scope for this variable.
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.
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 setFlags(unsigned F)
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
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
bool dominates(const MachineInstr *A, const MachineInstr *B) const
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
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.
This class contains meta information specific to a module.
const Module * getModule() const
LLVM_ABI MachineFunction * getMachineFunction(const Function &F) const
Returns the MachineFunction associated to IR function F if there is one, otherwise nullptr.
MachineOperand class - Representation of each machine instruction operand.
LLVM_ABI LLVM_READONLY MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
A Module instance is used to store all the information related to an LLVM module.
Wrapper class representing virtual and physical registers.
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
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.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
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.
Target - Wrapper for Target specific information.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
LLVM Value Representation.
An efficient, type-erasing, non-owning reference to a callable.
@ DW_OP_LLVM_fragment
Only used in LLVM metadata.
Scope
Defines the scope in which this symbol should be visible: Default – Visible in the public interface o...
NodeAddr< DefNode * > Def
BaseReg
Stack frame base register. Bit 0 of FREInfo.Info.
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.
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)
OutputIt copy_if(R &&Range, OutputIt Out, UnaryPredicate P)
Provide wrappers to std::copy_if which take ranges instead of having to pass begin/end explicitly.
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)
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
constexpr uint32_t Hi_32(uint64_t Value)
Return the high 32 bits of a 64 bit value.
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
constexpr uint32_t Lo_32(uint64_t Value)
Return the low 32 bits of a 64 bit value.
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)