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();
333 EnumCompileUnits.clear();
335 UniqueDebugLocations.clear();
336 GlobalVariableDebugInfoMap.clear();
337 LocalVariables.clear();
338 DebugLocalVariableRegs.clear();
339 DebugExpressionRegs.clear();
340 LexicalBlocks.clear();
341 DebugScopeRegs.clear();
342 ScopesInProgress.clear();
343 FailedScopes.clear();
344 DebugInlinedAtRegs.clear();
345 ScopeToPathOpStringReg.clear();
346 DebugSourceRegByFileStr.clear();
347 OpStringContentCache.clear();
348 ScalarTypeCache.clear();
349 ScalarConstantCache.clear();
350 ConstantValueRegs.clear();
351 DebugOperationCache.clear();
352 DebugExpressionCache.clear();
353 ModuleScopeIds.clear();
354 GlobalDIEmitted =
false;
355 GlobalNSDIEnabled =
false;
356 CurrentMAI =
nullptr;
358 NonSemanticOpStringsSectionEmitted =
false;
368 CompileUnitInfo Info;
371 Info.FilePath = File->getFilename();
374 File->getFilename());
377 Info.SpirvSourceLanguage = toNSDISrcLang(
CU->getSourceLanguage().getName());
378 CompileUnits.push_back(std::move(Info));
380 EnumCompileUnits.try_emplace(ET,
CU);
386 if (
const NamedMDNode *Flags = M->getNamedMetadata(
"llvm.module.flags")) {
387 for (
const auto *
Op : Flags->operands()) {
402 return Ty->getTag() != dwarf::DW_TAG_member;
411 G.getDebugInfo(GVEs);
422 GlobalVariableDebugInfoMap.try_emplace(
423 GV, GlobalVariableDebugInfo{Expr, DIGVToLLVMGV.
lookup(GV)});
440 if (
MI.getNumOperands() == 0 || !
MI.getOperand(0).isReg() ||
441 !
MI.getOperand(0).isDef())
448 if (CompileUnits.empty())
450 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_non_semantic_info))
464 ModuleScopeIds.insert(Id);
468void SPIRVNonSemanticDebugHandler::emitMCInst(
MCInst &Inst) {
473SPIRVNonSemanticDebugHandler::emitOpString(
StringRef S,
484MCRegister SPIRVNonSemanticDebugHandler::emitOpStringIfNew(
487 assert(!NonSemanticOpStringsSectionEmitted &&
488 "emitOpStringIfNew is only valid while emitting SPIR-V section 7");
490 auto [It,
Inserted] = OpStringContentCache.try_emplace(S, MCRegister());
492 It->second = emitOpString(S, MAI);
499 assert(NonSemanticOpStringsSectionEmitted &&
500 "getCachedOpStringReg requires emitNonSemanticDebugStrings() first");
502 auto It = OpStringContentCache.find(S);
503 assert(It != OpStringContentCache.end() &&
504 "NSDI OpString missing from cache; emitNonSemanticDebugStrings must "
505 "cache every string used in section 10");
509MCRegister SPIRVNonSemanticDebugHandler::emitAndCacheScopePathOpStringReg(
511 auto [It,
Inserted] = ScopeToPathOpStringReg.try_emplace(Scope, MCRegister());
513 It->second = emitOpStringIfNew(getDebugFullPath(Scope), MAI);
517MCRegister SPIRVNonSemanticDebugHandler::getCachedScopePathOpStringReg(
518 const DIScope *Scope,
bool UseEmptyPathIfNullScope) {
520 assert(UseEmptyPathIfNullScope &&
521 "null scope path lookup requires UseEmptyPathIfNullScope");
522 assert(CachedEmptyStringReg.isValid() &&
523 "empty path OpString must be cached in emitNonSemanticDebugStrings");
524 return CachedEmptyStringReg;
526 auto It = ScopeToPathOpStringReg.find(Scope);
527 assert(It != ScopeToPathOpStringReg.end() &&
528 "path OpString must be cached in emitNonSemanticDebugStrings");
529 MCRegister FileStrReg = It->second;
530 assert(FileStrReg.
isValid() &&
"path OpString id must be valid once cached");
534MCRegister SPIRVNonSemanticDebugHandler::emitOpConstantI32(
536 return findOrEmitConstant(SPIRV::OpConstantI, I32TypeReg,
Value,
540MCRegister SPIRVNonSemanticDebugHandler::emitExtInst(
541 SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
558MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeVoidReg(
560 if (!CachedOpTypeVoidReg.isValid())
561 CachedOpTypeVoidReg = findOrEmitOpTypeVoid(MAI);
562 return CachedOpTypeVoidReg;
565MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeInt32Reg(
567 if (!CachedOpTypeInt32Reg.isValid())
568 CachedOpTypeInt32Reg = findOrEmitOpTypeInt32(MAI);
569 return CachedOpTypeInt32Reg;
572MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeVoid(
575 if (
MI->getOpcode() == SPIRV::OpTypeVoid)
592 unsigned Width =
BT->getSizeInBits();
596MCRegister SPIRVNonSemanticDebugHandler::findOrEmitScalarType(
599 bool IsFloat =
BT->getEncoding() == dwarf::DW_ATE_float;
600 unsigned Opcode = IsBool ? SPIRV::OpTypeBool
601 : IsFloat ? SPIRV::OpTypeFloat
605 int64_t Width = IsBool ? 0 :
BT->getSizeInBits();
610 if (Opcode == SPIRV::OpTypeInt && Width == 32)
611 return getOrEmitOpTypeInt32Reg(MAI);
614 ScalarTypeCache.try_emplace({Opcode, Width}, MCRegister());
616 return CacheIt->second;
621 if (
MI->getOpcode() != Opcode)
623 if (IsBool || (
MI->getOperand(1).getImm() == Width &&
624 (IsFloat ||
MI->getOperand(2).getImm() == 0))) {
627 return CacheIt->second;
649 CacheIt->second =
Reg;
656 unsigned Words = IsWide ? 2 : 1;
657 if (
MI.getNumOperands() < 2 + Words)
660 for (
unsigned I = 0;
I < Words; ++
I) {
661 if (!
MI.getOperand(2 +
I).isImm())
667 return Found ==
Value;
670MCRegister SPIRVNonSemanticDebugHandler::findModuleConstant(
674 if (
MI->getOpcode() != Opcode ||
MI->getNumOperands() < 2)
688MCRegister SPIRVNonSemanticDebugHandler::findOrEmitConstant(
691 bool IsBool = Width == 0;
692 bool IsWide = Width == 64;
695 ScalarConstantCache.try_emplace({TypeReg.
id(),
Value}, MCRegister());
697 return CacheIt->second;
700 findModuleConstant(Opcode, TypeReg,
Value, IsBool, IsWide, MAI);
702 CacheIt->second = Found;
718 }
else if (Width == 16) {
725 CacheIt->second =
Reg;
729MCRegister SPIRVNonSemanticDebugHandler::findOrEmitScalarConstant(
731 MCRegister TypeReg = findOrEmitScalarType(
BT, MAI);
736 bool IsFloat =
BT->getEncoding() == dwarf::DW_ATE_float;
738 IsBool ? (
Value ? SPIRV::OpConstantTrue : SPIRV::OpConstantFalse)
739 : IsFloat ?
SPIRV::OpConstantF
740 :
SPIRV::OpConstantI;
741 return findOrEmitConstant(Opcode, TypeReg,
Value,
742 IsBool ? 0 :
BT->getSizeInBits(), MAI);
745MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeInt32(
748 if (
MI->getOpcode() == SPIRV::OpTypeInt &&
749 MI->getOperand(1).getImm() == 32 &&
MI->getOperand(2).getImm() == 0)
765auto SPIRVNonSemanticDebugHandler::getOrCreateDebugScope(
const DIScope *S)
766 -> EmitResult<MCRegister> {
767 if (!S || FailedScopes.contains(S))
768 return EmitResult<MCRegister>::unsupported();
769 if (
auto Reg = lookupOptReg(DebugScopeRegs, S))
770 return EmitResult<MCRegister>::emitted(*
Reg);
774 if (!ScopesInProgress.insert(S).second)
775 return EmitResult<MCRegister>::inProgress();
777 EmitResult<PreparedScope>
P = emitDebugScope(S);
778 ScopesInProgress.erase(S);
779 assert((!
P || !GlobalNSDIEnabled) &&
780 "debug type or scope created after module-scope NSDI emission");
782 if (
P.Status == EmitStatus::Unsupported)
783 FailedScopes.insert(S);
784 return P.Status == EmitStatus::InProgress
785 ? EmitResult<MCRegister>::inProgress()
792 emitExtInst(
P.Value->Opcode, getOrEmitOpTypeVoidReg(MAI),
794 DebugScopeRegs[S] =
Reg;
795 return EmitResult<MCRegister>::emitted(
Reg);
798auto SPIRVNonSemanticDebugHandler::emitDebugTypeBasic(
802 return EmitResult<PreparedScope>::unsupported();
804 MCRegister NameReg = getCachedOpStringReg(
BT->getName());
806 static_cast<uint32_t
>(
BT->getSizeInBits()), I32TypeReg, MAI);
810 unsigned Encoding = 0;
811 switch (
BT->getEncoding()) {
812 case dwarf::DW_ATE_address:
815 case dwarf::DW_ATE_boolean:
818 case dwarf::DW_ATE_float:
821 case dwarf::DW_ATE_signed:
824 case dwarf::DW_ATE_signed_char:
827 case dwarf::DW_ATE_unsigned:
830 case dwarf::DW_ATE_unsigned_char:
834 MCRegister EncodingReg = emitOpConstantI32(Encoding, I32TypeReg, MAI);
835 MCRegister FlagsReg = emitOpConstantI32(0, I32TypeReg, MAI);
836 return EmitResult<PreparedScope>::emitted(
837 PreparedScope{SPIRV::NonSemanticExtInst::DebugTypeBasic,
838 {NameReg, SizeReg, EncodingReg, FlagsReg}});
841auto SPIRVNonSemanticDebugHandler::emitDebugScope(
const DIScope *S)
842 -> EmitResult<PreparedScope> {
843 assert(CurrentMAI &&
"emitDebugScope requires CurrentMAI");
846 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
847 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
850 return emitDebugTypeBasic(
BT, I32TypeReg, MAI);
852 return emitDebugTypeFunctionForSubroutineType(ST, MAI);
854 return emitDebugTypeForCompositeType(CT, VoidTypeReg, I32TypeReg,
857 return emitDebugTypeForDerivedType(DT, VoidTypeReg, I32TypeReg,
860 return emitDebugLexicalBlock(S, VoidTypeReg, I32TypeReg, ExtInstSetReg,
863 if (
SP->isDefinition())
864 return emitDebugFunction(SP, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
865 return emitDebugFunctionDeclaration(SP, VoidTypeReg, I32TypeReg,
868 return EmitResult<PreparedScope>::unsupported();
871auto SPIRVNonSemanticDebugHandler::emitDebugTypeForCompositeType(
874 -> EmitResult<PreparedScope> {
875 switch (CT->getTag()) {
876 case dwarf::DW_TAG_array_type:
889 return emitDebugTypeVector(CT, MAI);
890 return emitDebugTypeArray(CT, MAI);
891 case dwarf::DW_TAG_structure_type:
892 case dwarf::DW_TAG_class_type:
893 case dwarf::DW_TAG_union_type:
894 return emitDebugTypeComposite(CT, VoidTypeReg, I32TypeReg, ExtInstSetReg,
896 case dwarf::DW_TAG_enumeration_type:
897 return emitDebugTypeEnum(CT, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
899 return EmitResult<PreparedScope>::unsupported();
903auto SPIRVNonSemanticDebugHandler::emitDebugTypeForDerivedType(
906 -> EmitResult<PreparedScope> {
907 switch (DT->getTag()) {
908 case dwarf::DW_TAG_pointer_type:
909 return emitDebugTypePointer(DT, MAI);
910 case dwarf::DW_TAG_typedef:
911 return emitDebugTypedef(DT, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
912 case dwarf::DW_TAG_member:
913 return emitDebugTypeMember(DT, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
915 return EmitResult<PreparedScope>::unsupported();
919auto SPIRVNonSemanticDebugHandler::emitDebugTypePointer(
921 -> EmitResult<PreparedScope> {
924 if (!PT->getDWARFAddressSpace().has_value())
925 return EmitResult<PreparedScope>::unsupported();
928 if (
const DIType *BaseTy = PT->getBaseType()) {
929 EmitResult<MCRegister>
Base = getOrCreateDebugScope(BaseTy);
931 return EmitResult<PreparedScope>::failure(
Base);
938 BaseReg = CachedDebugInfoNoneReg;
941 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
943 emitOpConstantI32(transDebugFlags(PT), I32TypeReg, MAI);
948 MCRegister StorageClassReg = emitOpConstantI32(
952 return EmitResult<PreparedScope>::emitted(
953 PreparedScope{SPIRV::NonSemanticExtInst::DebugTypePointer,
954 {
BaseReg, StorageClassReg, DebugTypePointerFlagsReg}});
957auto SPIRVNonSemanticDebugHandler::emitDebugTypeFunctionForSubroutineType(
959 -> EmitResult<PreparedScope> {
960 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
961 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
963 emitOpConstantI32(transDebugFlags(ST), I32TypeReg, MAI);
964 DITypeArray
TA =
ST->getTypeArray();
971 Ops.push_back(VoidTypeReg);
973 for (
unsigned I = 0,
E =
TA.size();
I !=
E; ++
I) {
974 bool IsReturnType = (
I == 0);
975 EmitResult<MCRegister>
Slot =
976 mapDISignatureTypeToReg(TA[
I], VoidTypeReg, IsReturnType);
980 return EmitResult<PreparedScope>::failure(Slot);
984 return EmitResult<PreparedScope>::emitted(
985 PreparedScope{SPIRV::NonSemanticExtInst::DebugTypeFunction,
Ops});
989SPIRVNonSemanticDebugHandler::EmitResult<MCRegister>
990SPIRVNonSemanticDebugHandler::resolveScope(
const DIScope *Scope,
994 Scope = DLBF->getScope();
997 return getOrCreateDebugScope(Scope);
1000 auto CUResult = [](std::optional<MCRegister>
Reg) {
1001 return Reg ? EmitResult<MCRegister>::emitted(*
Reg)
1005 return CUResult(lookupOptReg(DebugScopeRegs, FallbackCU));
1007 if (CompileUnits.empty())
1008 return EmitResult<MCRegister>::unsupported();
1010 return CUResult(lookupOptReg(DebugScopeRegs, CompileUnits[0].TheCU));
1013auto SPIRVNonSemanticDebugHandler::emitDebugLexicalBlock(
1016 -> EmitResult<PreparedScope> {
1018 "S must be a DILexicalBlock or DINamespace in emitDebugLexicalBlock");
1019 EmitResult<MCRegister> Parent =
resolveScope(S->getScope());
1021 return EmitResult<PreparedScope>::failure(Parent);
1023 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1024 S->getFile(),
true);
1025 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1026 ExtInstSetReg, MAI);
1030 MCRegister LineReg = emitOpConstantI32(
static_cast<uint32_t
>(LB->getLine()),
1033 static_cast<uint32_t
>(LB->getColumn()), I32TypeReg, MAI);
1034 Ops = {SrcReg, LineReg, ColReg, *Parent.Value};
1038 MCRegister LineReg = emitOpConstantI32(0, I32TypeReg, MAI);
1039 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
1040 MCRegister NameReg = getCachedOpStringReg(NS->getName());
1041 Ops = {SrcReg, LineReg, ColReg, *Parent.Value, NameReg};
1044 return EmitResult<PreparedScope>::emitted(
1045 PreparedScope{SPIRV::NonSemanticExtInst::DebugLexicalBlock,
Ops});
1048MCRegister SPIRVNonSemanticDebugHandler::getOrEmitDebugInlinedAt(
1051 assert(IA &&
"IA must not be null in getOrEmitDebugInlinedAt");
1053 if (MCRegister Cached = DebugInlinedAtRegs.lookup(IA))
1056 EmitResult<MCRegister>
Scope = resolveScope(
IA->getScope());
1058 return MCRegister();
1060 MCRegister LineReg =
1061 emitOpConstantI32(
static_cast<uint32_t
>(
IA->getLine()), I32TypeReg, MAI);
1066 if (
const DILocation *Outer =
IA->getInlinedAt()) {
1067 MCRegister OuterReg = getOrEmitDebugInlinedAt(
1068 Outer, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
1070 return MCRegister();
1071 Ops.push_back(OuterReg);
1074 MCRegister
Reg = emitExtInst(SPIRV::NonSemanticExtInst::DebugInlinedAt,
1075 VoidTypeReg, ExtInstSetReg,
Ops, MAI);
1076 DebugInlinedAtRegs[
IA] =
Reg;
1080auto SPIRVNonSemanticDebugHandler::emitDebugFunctionDeclaration(
1083 -> EmitResult<PreparedScope> {
1084 assert(SP &&
"SP must not be null in emitDebugFunctionDeclaration");
1086 "SP must not be a definition in emitDebugFunctionDeclaration");
1089 EmitResult<MCRegister> FnTy = getOrCreateDebugScope(
SP->getType());
1091 return EmitResult<PreparedScope>::failure(FnTy);
1093 EmitResult<MCRegister> Parent =
resolveScope(
SP->getScope(),
SP->getUnit());
1095 return EmitResult<PreparedScope>::failure(Parent);
1097 MCRegister FileStrReg = getCachedScopePathOpStringReg(SP);
1099 MCRegister NameReg = getCachedOpStringReg(
SP->getName());
1100 MCRegister LinkageReg = getCachedOpStringReg(
SP->getLinkageName());
1101 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1102 ExtInstSetReg, MAI);
1105 emitOpConstantI32(
static_cast<uint32_t
>(
SP->getLine()), I32TypeReg, MAI);
1106 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
1108 uint32_t FlagsVal = transDebugFlags(SP);
1111 FlagsVal &= ~NSDIFlagIsDefinition;
1112 MCRegister FlagsReg = emitOpConstantI32(FlagsVal, I32TypeReg, MAI);
1114 return EmitResult<PreparedScope>::emitted(
1115 PreparedScope{SPIRV::NonSemanticExtInst::DebugFunctionDeclaration,
1116 {NameReg, *FnTy.Value, SrcReg, LineReg, ColReg,
1117 *Parent.Value, LinkageReg, FlagsReg}});
1120auto SPIRVNonSemanticDebugHandler::emitDebugFunction(
1123 -> EmitResult<PreparedScope> {
1124 assert(SP &&
"SP must not be null in emitDebugFunction");
1125 assert(
SP->isDefinition() &&
"SP must be a definition in emitDebugFunction");
1127 EmitResult<MCRegister> FnTy = getOrCreateDebugScope(
SP->getType());
1129 return EmitResult<PreparedScope>::failure(FnTy);
1131 EmitResult<MCRegister> Parent =
resolveScope(
SP->getScope(),
SP->getUnit());
1133 return EmitResult<PreparedScope>::failure(Parent);
1135 MCRegister NameReg = getCachedOpStringReg(
SP->getName());
1136 MCRegister LinkageReg = getCachedOpStringReg(
SP->getLinkageName());
1137 MCRegister FileStrReg = getCachedScopePathOpStringReg(SP);
1138 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1139 ExtInstSetReg, MAI);
1142 emitOpConstantI32(
static_cast<uint32_t
>(
SP->getLine()), I32TypeReg, MAI);
1145 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
1146 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(SP), I32TypeReg, MAI);
1148 static_cast<uint32_t
>(
SP->getScopeLine()), I32TypeReg, MAI);
1151 LineReg, ColReg, *Parent.Value,
1152 LinkageReg, FlagsReg, ScopeLineReg};
1155 EmitResult<MCRegister> DeclRes = getOrCreateDebugScope(Decl);
1157 Ops.push_back(*DeclRes.Value);
1160 return EmitResult<PreparedScope>::emitted(
1161 PreparedScope{SPIRV::NonSemanticExtInst::DebugFunction,
Ops});
1164auto SPIRVNonSemanticDebugHandler::mapDISignatureTypeToReg(
1166 -> EmitResult<MCRegister> {
1169 return EmitResult<MCRegister>::emitted(VoidTypeReg);
1170 assert(CachedDebugInfoNoneReg.isValid() &&
1171 "DebugInfoNone must be emitted before DISubroutineType operands");
1172 return EmitResult<MCRegister>::emitted(CachedDebugInfoNoneReg);
1174 return getOrCreateDebugScope(Ty);
1192static std::optional<NonSemanticDebugOp>
1195 case dwarf::DW_OP_deref:
1197 case dwarf::DW_OP_plus:
1199 case dwarf::DW_OP_minus:
1201 case dwarf::DW_OP_plus_uconst:
1203 case dwarf::DW_OP_bit_piece:
1205 case dwarf::DW_OP_swap:
1207 case dwarf::DW_OP_xderef:
1209 case dwarf::DW_OP_stack_value:
1211 case dwarf::DW_OP_constu:
1216 return std::nullopt;
1222static std::optional<SmallVector<uint32_t, 3>>
1224 std::optional<NonSemanticDebugOp> NSOp =
1227 return std::nullopt;
1230 for (
unsigned I = 0,
E =
Op.getNumArgs();
I !=
E; ++
I) {
1233 return std::nullopt;
1239std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugOperation(
1245 return std::nullopt;
1247 auto [It,
Inserted] = DebugOperationCache.try_emplace(std::move(*
Key));
1252 for (uint32_t V : It->first)
1253 Operands.push_back(emitOpConstantI32(V, I32TypeReg, MAI));
1254 MCRegister
Reg = emitExtInst(SPIRV::NonSemanticExtInst::DebugOperation,
1255 VoidTypeReg, ExtInstSetReg,
Operands, MAI);
1260std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugExpression(
1263 assert(Expr &&
"Expr must not be null in emitDebugExpression");
1266 for (
const DIExpression::ExprOperand &
Op : Expr->
expr_ops()) {
1267 std::optional<MCRegister> OpReg =
1268 emitDebugOperation(
Op, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
1270 return std::nullopt;
1275 DebugExpressionCache.try_emplace(std::move(OperationRegs));
1279 MCRegister
Reg = emitExtInst(SPIRV::NonSemanticExtInst::DebugExpression,
1280 VoidTypeReg, ExtInstSetReg, It->first, MAI);
1285std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugGlobalVariable(
1289 assert(GV &&
"GV must not be null in emitDebugGlobalVariable");
1291 EmitResult<MCRegister> Parent = resolveScope(GV->
getScope());
1293 return std::nullopt;
1295 MCRegister ParentReg = *Parent.Value;
1301 MCRegister TyReg = CachedDebugInfoNoneReg;
1302 if (
const DIType *Ty = GV->
getType()) {
1303 auto TyRegOpt = lookupOptReg(DebugScopeRegs, Ty);
1305 return std::nullopt;
1309 std::optional<MCRegister> StaticMemberRegOpt;
1312 StaticMemberRegOpt = lookupOptReg(DebugScopeRegs, SM);
1313 if (!StaticMemberRegOpt)
1314 return std::nullopt;
1317 MCRegister NameReg = getCachedOpStringReg(GV->
getName());
1318 MCRegister LinkageReg = getCachedOpStringReg(GV->
getLinkageName());
1319 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1321 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1322 ExtInstSetReg, MAI);
1324 MCRegister LineReg =
1325 emitOpConstantI32(
static_cast<uint32_t
>(GV->
getLine()), I32TypeReg, MAI);
1329 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
1336 MCRegister VariableReg = CachedDebugInfoNoneReg;
1337 if (
const GlobalVariable *LLVMGV =
Info.LLVMGV) {
1340 VariableReg = GVReg;
1341 }
else if (
Info.Expr &&
Info.Expr->getNumElements() != 0) {
1342 if (
auto ExprReg = emitDebugExpression(
Info.Expr, VoidTypeReg, I32TypeReg,
1343 ExtInstSetReg, MAI))
1344 VariableReg = *ExprReg;
1347 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(GV), I32TypeReg, MAI);
1350 LineReg, ColReg, ParentReg,
1351 LinkageReg, VariableReg, FlagsReg};
1353 if (StaticMemberRegOpt)
1354 Ops.push_back(*StaticMemberRegOpt);
1356 return emitExtInst(SPIRV::NonSemanticExtInst::DebugGlobalVariable,
1357 VoidTypeReg, ExtInstSetReg,
Ops, MAI);
1360std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugLocalVariable(
1363 assert(LV &&
"LV must not be null in emitDebugLocalVariable");
1365 EmitResult<MCRegister> Parent = resolveScope(LV->
getScope());
1367 return std::nullopt;
1369 MCRegister TyReg = CachedDebugInfoNoneReg;
1370 if (
const DIType *Ty = LV->
getType()) {
1371 auto TyRegOpt = lookupOptReg(DebugScopeRegs, Ty);
1373 return std::nullopt;
1377 MCRegister NameReg = getCachedOpStringReg(LV->
getName());
1378 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1380 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1381 ExtInstSetReg, MAI);
1382 MCRegister LineReg =
1383 emitOpConstantI32(
static_cast<uint32_t
>(LV->
getLine()), I32TypeReg, MAI);
1385 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
1386 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(LV), I32TypeReg, MAI);
1389 ColReg, *Parent.Value, FlagsReg};
1390 if (
unsigned Arg = LV->
getArg())
1391 Ops.push_back(emitOpConstantI32(Arg, I32TypeReg, MAI));
1393 return emitExtInst(SPIRV::NonSemanticExtInst::DebugLocalVariable, VoidTypeReg,
1394 ExtInstSetReg,
Ops, MAI);
1397auto SPIRVNonSemanticDebugHandler::emitDebugTypeVector(
1399 -> EmitResult<PreparedScope> {
1402 return EmitResult<PreparedScope>::unsupported();
1406 DINodeArray
Elements = VT->getElements();
1408 return EmitResult<PreparedScope>::unsupported();
1412 return EmitResult<PreparedScope>::unsupported();
1414 EmitResult<MCRegister>
Base = getOrCreateDebugScope(BaseTy);
1416 return EmitResult<PreparedScope>::failure(
Base);
1418 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
1420 static_cast<uint32_t
>(CI->getZExtValue()), I32TypeReg, MAI);
1421 return EmitResult<PreparedScope>::emitted(PreparedScope{
1422 SPIRV::NonSemanticExtInst::DebugTypeVector, {*
Base.Value, CountReg}});
1425auto SPIRVNonSemanticDebugHandler::emitDebugTypeArray(
1427 -> EmitResult<PreparedScope> {
1430 EmitResult<MCRegister>
Base = getOrCreateDebugScope(AT->getBaseType());
1432 return EmitResult<PreparedScope>::failure(
Base);
1434 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
1442 for (
const DINode *Element : AT->getElements()) {
1454 if (
Value.getActiveBits() <= 32)
1455 Count =
static_cast<uint32_t
>(
Value.getZExtValue());
1457 Ops.push_back(emitOpConstantI32(
Count, I32TypeReg, MAI));
1460 return EmitResult<PreparedScope>::emitted(
1461 PreparedScope{SPIRV::NonSemanticExtInst::DebugTypeArray,
Ops});
1464auto SPIRVNonSemanticDebugHandler::emitDebugTypeMember(
1467 -> EmitResult<PreparedScope> {
1468 EmitResult<MCRegister> Ty = getOrCreateDebugScope(
M->getBaseType());
1470 return EmitResult<PreparedScope>::failure(Ty);
1473 return EmitResult<PreparedScope>::unsupported();
1475 MCRegister NameReg = getCachedOpStringReg(
M->getName());
1476 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1477 M->getFile(),
true);
1478 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1479 ExtInstSetReg, MAI);
1481 emitOpConstantI32(
static_cast<uint32_t
>(
M->getLine()), I32TypeReg, MAI);
1484 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
1486 static_cast<uint32_t
>(
M->getOffsetInBits()), I32TypeReg, MAI);
1488 static_cast<uint32_t
>(
M->getSizeInBits()), I32TypeReg, MAI);
1489 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(M), I32TypeReg, MAI);
1500 return EmitResult<PreparedScope>::emitted(
1501 PreparedScope{SPIRV::NonSemanticExtInst::DebugTypeMember,
1502 {NameReg, *Ty.Value, SrcReg, LineReg, ColReg, OffsetReg,
1503 SizeReg, FlagsReg}});
1506auto SPIRVNonSemanticDebugHandler::emitDebugTypeComposite(
1509 -> EmitResult<PreparedScope> {
1512 EmitResult<MCRegister> Parent =
resolveScope(CT->getScope());
1514 return EmitResult<PreparedScope>::failure(Parent);
1517 return EmitResult<PreparedScope>::unsupported();
1520 for (
const DINode *Element : CT->getElements()) {
1522 if (!M ||
M->getTag() != dwarf::DW_TAG_member)
1524 EmitResult<MCRegister>
Member = getOrCreateDebugScope(M);
1529 MCRegister NameReg = getCachedOpStringReg(CT->getName());
1530 MCRegister LinkageReg = getCachedOpStringReg(CT->getIdentifier());
1531 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1532 CT->getFile(),
true);
1533 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1534 ExtInstSetReg, MAI);
1537 emitOpConstantI32(mapCompositeTypeTag(CT->getTag()), I32TypeReg, MAI);
1539 emitOpConstantI32(
static_cast<uint32_t
>(CT->getLine()), I32TypeReg, MAI);
1540 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
1544 if (!CT->isForwardDecl())
1545 SizeReg = emitOpConstantI32(
static_cast<uint32_t
>(CT->getSizeInBits()),
1548 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(CT), I32TypeReg, MAI);
1551 LineReg, ColReg, *Parent.Value,
1552 LinkageReg, SizeReg, FlagsReg};
1554 return EmitResult<PreparedScope>::emitted(
1555 PreparedScope{SPIRV::NonSemanticExtInst::DebugTypeComposite,
Ops});
1558auto SPIRVNonSemanticDebugHandler::emitDebugTypeEnum(
1561 -> EmitResult<PreparedScope> {
1565 return EmitResult<PreparedScope>::unsupported();
1567 MCRegister UnderlyingReg = CachedDebugInfoNoneReg;
1568 if (
const DIType *BaseTy = ET->getBaseType()) {
1569 EmitResult<MCRegister>
Base = getOrCreateDebugScope(BaseTy);
1571 return EmitResult<PreparedScope>::failure(
Base);
1572 UnderlyingReg = *
Base.Value;
1575 EmitResult<MCRegister> Parent =
1576 resolveScope(ET->getScope(), EnumCompileUnits.lookup(ET));
1578 return EmitResult<PreparedScope>::failure(Parent);
1580 MCRegister NameReg = getCachedOpStringReg(ET->getName());
1581 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1582 ET->getFile(),
true);
1583 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1584 ExtInstSetReg, MAI);
1586 emitOpConstantI32(
static_cast<uint32_t
>(ET->getLine()), I32TypeReg, MAI);
1588 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
1590 emitOpConstantI32(
static_cast<uint32_t
>(
Size), I32TypeReg, MAI);
1591 MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(ET), I32TypeReg, MAI);
1594 ColReg, *Parent.Value, SizeReg, FlagsReg};
1599 for (
const DINode *Element : ET->getElements()) {
1604 if (
E->isUnsigned() ? !
Value.isIntN(32) : !
Value.isSignedIntN(32))
1606 uint32_t
Bits =
E->isUnsigned()
1607 ?
static_cast<uint32_t
>(
Value.getZExtValue())
1608 :
static_cast<uint32_t
>(
Value.getSExtValue());
1609 Ops.push_back(emitOpConstantI32(Bits, I32TypeReg, MAI));
1610 Ops.push_back(getCachedOpStringReg(
E->getName()));
1613 return EmitResult<PreparedScope>::emitted(
1614 PreparedScope{SPIRV::NonSemanticExtInst::DebugTypeEnum,
Ops});
1617auto SPIRVNonSemanticDebugHandler::emitDebugTypedef(
1620 -> EmitResult<PreparedScope> {
1621 EmitResult<MCRegister>
Base = getOrCreateDebugScope(TD->getBaseType());
1623 return EmitResult<PreparedScope>::failure(
Base);
1625 MCRegister NameReg = getCachedOpStringReg(TD->getName());
1626 MCRegister FileStrReg = getCachedScopePathOpStringReg(
1627 TD->getFile(),
true);
1628 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
1629 ExtInstSetReg, MAI);
1631 emitOpConstantI32(
static_cast<uint32_t
>(TD->getLine()), I32TypeReg, MAI);
1633 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
1638 EmitResult<MCRegister> Parent =
resolveScope(TD->getScope());
1640 return EmitResult<PreparedScope>::failure(Parent);
1642 return EmitResult<PreparedScope>::emitted(PreparedScope{
1643 SPIRV::NonSemanticExtInst::DebugTypedef,
1644 {NameReg, *
Base.Value, SrcReg, LineReg, ColReg, *Parent.Value}});
1649 if (CompileUnits.empty())
1657 for (
const CompileUnitInfo &Info : CompileUnits) {
1659 MCRegister PathReg = emitOpStringIfNew(Info.FilePath, MAI);
1660 ScopeToPathOpStringReg[Info.TheCU] = PathReg;
1661 if (
const DIFile *
F = Info.TheCU->getFile())
1662 ScopeToPathOpStringReg[
F] = PathReg;
1667 emitOpStringIfNew(SP->getName(), MAI);
1668 emitOpStringIfNew(SP->getLinkageName(), MAI);
1669 emitAndCacheScopePathOpStringReg(SP, MAI);
1672 for (
const DIType *Ty : DebugTypes) {
1674 emitOpStringIfNew(
BT->getName(), MAI);
1680 if (CT->getTag() == dwarf::DW_TAG_enumeration_type) {
1681 emitOpStringIfNew(CT->getName(), MAI);
1682 emitAndCacheScopePathOpStringReg(CT->getFile(), MAI);
1683 for (
const DINode *Element : CT->getElements())
1685 emitOpStringIfNew(E->getName(), MAI);
1691 if (CT->getTag() != dwarf::DW_TAG_structure_type &&
1692 CT->getTag() != dwarf::DW_TAG_class_type &&
1693 CT->getTag() != dwarf::DW_TAG_union_type)
1695 emitOpStringIfNew(CT->getName(), MAI);
1696 emitOpStringIfNew(CT->getIdentifier(), MAI);
1697 emitAndCacheScopePathOpStringReg(CT->getFile(), MAI);
1698 for (
const DINode *Element : CT->getElements()) {
1700 if (!M || M->getTag() != dwarf::DW_TAG_member)
1702 emitOpStringIfNew(M->getName(), MAI);
1703 emitAndCacheScopePathOpStringReg(M->getFile(), MAI);
1709 if (TD && TD->getTag() == dwarf::DW_TAG_typedef) {
1710 emitOpStringIfNew(TD->getName(), MAI);
1711 emitAndCacheScopePathOpStringReg(TD->getFile(), MAI);
1715 for (
const auto &[GV,
_] : GlobalVariableDebugInfoMap) {
1716 emitOpStringIfNew(GV->
getName(), MAI);
1718 emitAndCacheScopePathOpStringReg(GV->
getFile(), MAI);
1722 emitOpStringIfNew(LV->
getName(), MAI);
1723 emitAndCacheScopePathOpStringReg(LV->
getFile(), MAI);
1728 for (
const DIScope *S : LexicalBlocks) {
1729 emitAndCacheScopePathOpStringReg(S->getFile(), MAI);
1731 emitOpStringIfNew(NS->getName(), MAI);
1735 emitAndCacheScopePathOpStringReg(
DL->getScope(), MAI);
1737 CachedEmptyStringReg = emitOpStringIfNew(
"", MAI);
1740 NonSemanticOpStringsSectionEmitted =
true;
1744void SPIRVNonSemanticDebugHandler::emitDebugFunctionDefinition(
1748 "DebugFunctionDefinition operands must be valid");
1749 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
1751 emitExtInst(SPIRV::NonSemanticExtInst::DebugFunctionDefinition, VoidTypeReg,
1752 ExtInstSetReg, {DebugFunctionReg, OpFunctionReg}, MAI);
1755void SPIRVNonSemanticDebugHandler::resetPerFunctionDebugState() {
1756 CurrentMF =
nullptr;
1757 LastFunctionOpVariable =
nullptr;
1758 DebugFunctionDefinitionEmitted =
false;
1759 LastLineMI =
nullptr;
1760 LastScopeMI =
nullptr;
1764void SPIRVNonSemanticDebugHandler::preparePerFunctionDebug(
1766 resetPerFunctionDebugState();
1767 if (!GlobalNSDIEnabled || !CurrentMAI)
1778 if (!SP || !
SP->isDefinition())
1783 LastFunctionOpVariable =
1784 findLastFunctionOpVariableDeclaration(*MF, *CurrentMAI);
1786 analyzeDebugRecords(*MF);
1789void SPIRVNonSemanticDebugHandler::tryEmitDebugFunctionDefinition(
1791 if (DebugFunctionDefinitionEmitted || !GlobalNSDIEnabled)
1794 assert(CurrentMF &&
"no current MachineFunction");
1795 const Function &
F = CurrentMF->getFunction();
1796 const DISubprogram *
SP =
F.getSubprogram();
1797 if (!SP || !
SP->isDefinition())
1800 auto DFIt = DebugScopeRegs.find(SP);
1801 if (DFIt == DebugScopeRegs.end())
1808 emitDebugFunctionDefinition(DFIt->second, OpFunctionReg, MAI);
1809 DebugFunctionDefinitionEmitted =
true;
1814 preparePerFunctionDebug(MF);
1819 resetPerFunctionDebugState();
1826 if (!DebugFunctionDefinitionEmitted)
1829 emitAnalyzedRecords(
MI);
1831 std::optional<const MachineInstr *>
Target = resolveDebugLocTarget(
MI);
1835 (void)emitDebugScopeForInstruction(*
Target);
1836 emitDebugLineForInstruction(*
Target);
1846static std::optional<Register>
1850 if (!
MI.isIndirectDebugValue())
1851 return std::nullopt;
1855 Register LocReg =
MI.getDebugOperand(0).getReg();
1857 return std::nullopt;
1868 const MachineInstr *Def =
MI.getMF()->getRegInfo().getUniqueVRegDef(LocReg);
1869 if (!Def || Def->getOpcode() != SPIRV::OpVariable)
1870 return std::nullopt;
1875void SPIRVNonSemanticDebugHandler::emitDebugBinding(
1876 SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
1878 assert(DebugFunctionDefinitionEmitted &&
1879 "DebugFunctionDefinition must be emitted");
1880 assert(CurrentMAI &&
"CurrentMAI must be set");
1882 auto VarRegOpt = lookupOptReg(DebugLocalVariableRegs,
MI->getDebugVariable());
1886 auto ExprRegOpt = lookupOptReg(DebugExpressionRegs,
MI->getDebugExpression());
1890 if (!emitDebugScopeForInstruction(
MI))
1892 emitDebugLineForInstruction(
MI);
1894 SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI;
1895 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
1897 emitExtInst(Opcode, VoidTypeReg, ExtInstSetReg,
1898 {*VarRegOpt, LocationReg, *ExprRegOpt}, MAI);
1903static std::optional<std::pair<const DIBasicType *, uint64_t>>
1905 if (!
MI.isNonListDebugValue() ||
MI.isIndirectDebugValue())
1906 return std::nullopt;
1910 return std::nullopt;
1915 return std::nullopt;
1920 else if (
Value.isCImm())
1924 return std::make_pair(
BT, Bits);
1927std::optional<MCRegister> SPIRVNonSemanticDebugHandler::getConstantValueReg(
1929 std::optional<std::pair<const DIBasicType *, uint64_t>>
Const =
1932 return std::nullopt;
1934 auto It = ConstantValueRegs.find(*Const);
1935 if (It == ConstantValueRegs.end() || !It->second.isValid())
1936 return std::nullopt;
1941 if (!
MI.isNonListDebugValue() ||
MI.isIndirectDebugValue())
1942 return std::nullopt;
1946 return std::nullopt;
1950 return std::nullopt;
1952 const MachineInstr *Def =
MI.getMF()->getRegInfo().getUniqueVRegDef(ValueReg);
1953 if (!Def || (Def->isPseudo() && !Def->isPHI()) || Def->isMetaInstruction() ||
1954 Def->getNumOperands() == 0 || !Def->getOperand(0).isReg() ||
1955 !Def->getOperand(0).isDef() || Def->getOperand(0).getReg() != ValueReg)
1956 return std::nullopt;
1962 return Opcode == SPIRV::OpSelectionMerge || Opcode == SPIRV::OpLoopMerge ||
1963 Opcode == SPIRV::OpLoopControlINTEL;
1975 switch (
MI->getOpcode()) {
1976 case SPIRV::OpFunction:
1977 case SPIRV::OpFunctionParameter:
1978 case SPIRV::OpFunctionEnd:
1979 case SPIRV::OpLabel:
1980 case TargetOpcode::PHI:
1991 :
MI->getPrevNode();
1992 Adj; Adj = Forward ? Adj->getNextNode() : Adj->getPrevNode()) {
2000std::optional<const MachineInstr *>
2001SPIRVNonSemanticDebugHandler::resolveDebugLocTarget(
const MachineInstr *
MI) {
2002 assert(CurrentMAI &&
"CurrentMAI must be set");
2003 SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI;
2008 return std::nullopt;
2016 return std::nullopt;
2022 assert(
MI &&
"Merge instruction must be followed by a terminator");
2026 return std::nullopt;
2032void SPIRVNonSemanticDebugHandler::resolveDebugRecord(
2035 SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI;
2041 const MachineInstr *Anchor =
2051 placeRecord(SPIRV::NonSemanticExtInst::DebugDeclare,
MI, StorageReg,
2056 if (std::optional<MCRegister> ConstReg = getConstantValueReg(
MI)) {
2057 placeRecord(SPIRV::NonSemanticExtInst::DebugValue,
MI, *ConstReg, Anchor);
2077 if (ModuleScopeIds.contains(ValueReg) ||
2079 placeRecord(SPIRV::NonSemanticExtInst::DebugValue,
MI, ValueReg, Anchor);
2082void SPIRVNonSemanticDebugHandler::analyzeDebugRecords(
2084 assert(CurrentMAI &&
"CurrentMAI must be set");
2088 std::optional<MachineDominatorTree> DomTree;
2090 for (
const MachineBasicBlock &
MBB : MF) {
2091 const MachineInstr *LastEmitted =
nullptr;
2092 for (
const MachineInstr &
MI :
MBB) {
2093 if (
MI.isDebugValueLike()) {
2096 resolveDebugRecord(
MI, LastEmitted, *DomTree);
2105void SPIRVNonSemanticDebugHandler::placeRecord(
2106 SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
2109 Records[Anchor].push_back({&
MI, Opcode, LocationReg});
2112void SPIRVNonSemanticDebugHandler::emitAnalyzedRecords(
2114 auto It = Records.find(Anchor);
2115 if (It == Records.end())
2117 for (
const DebugRecord &R : It->second)
2118 emitDebugBinding(
R.Opcode,
R.MI,
R.LocationReg);
2121bool SPIRVNonSemanticDebugHandler::emitDebugScopeForInstruction(
2123 assert(DebugFunctionDefinitionEmitted &&
2124 "DebugFunctionDefinition must be emitted");
2125 assert(CurrentMAI &&
"CurrentMAI must be set");
2130 if (LastScopeMI &&
MI->getParent() != LastScopeMI->getParent())
2131 LastScopeMI =
nullptr;
2133 SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI;
2134 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
2137 const DILocation *CurDL =
MI->getDebugLoc().get();
2142 emitExtInst(SPIRV::NonSemanticExtInst::DebugNoScope, VoidTypeReg,
2143 ExtInstSetReg, {}, MAI);
2144 LastScopeMI =
nullptr;
2149 const DIScope *CurScope = CurDL->getScope();
2150 const DILocation *CurInlinedAt = CurDL->getInlinedAt();
2153 const DILocation *LastDL = LastScopeMI->getDebugLoc().get();
2154 if (LastDL->getScope() == CurScope &&
2155 LastDL->getInlinedAt() == CurInlinedAt)
2159 EmitResult<MCRegister> CurScopeRes = resolveScope(CurScope);
2166 MCRegister InlinedReg = DebugInlinedAtRegs.lookup(CurInlinedAt);
2169 Ops.push_back(InlinedReg);
2173 emitExtInst(SPIRV::NonSemanticExtInst::DebugScope, VoidTypeReg, ExtInstSetReg,
2180void SPIRVNonSemanticDebugHandler::emitDebugLineForInstruction(
2182 assert(DebugFunctionDefinitionEmitted &&
2183 "DebugFunctionDefinition must be emitted");
2184 assert(CurrentMAI &&
"CurrentMAI must be set");
2189 if (LastLineMI &&
MI->getParent() != LastLineMI->getParent())
2190 LastLineMI =
nullptr;
2192 SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI;
2193 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
2196 const DILocation *
DL =
MI->getDebugLoc().get();
2201 emitExtInst(SPIRV::NonSemanticExtInst::DebugNoLine, VoidTypeReg,
2202 ExtInstSetReg, {}, MAI);
2203 LastLineMI =
nullptr;
2213 MCRegister FileStrReg = getCachedScopePathOpStringReg(
2214 DL->getScope(),
true);
2215 unsigned Line =
DL->getLine();
2216 unsigned Col =
DL->getColumn();
2218 unsigned I32TypeId = CachedOpTypeInt32Reg.id();
2219 MCRegister SrcReg = DebugSourceRegByFileStr.lookup(FileStrReg.
id());
2220 MCRegister LineReg = ScalarConstantCache.lookup({I32TypeId,
Line});
2221 MCRegister ColStartReg = ScalarConstantCache.lookup({I32TypeId, Col});
2222 MCRegister ColEndReg = ScalarConstantCache.lookup({I32TypeId, Col + 1});
2234 if (LastLineMI &&
MI->getDebugLoc() == LastLineMI->getDebugLoc())
2238 emitExtInst(SPIRV::NonSemanticExtInst::DebugLine, VoidTypeReg, ExtInstSetReg,
2239 {SrcReg, LineReg, LineReg, ColStartReg, ColEndReg}, MAI);
2248 if (!
MI || !GlobalNSDIEnabled || !CurrentMF)
2251 if (DebugFunctionDefinitionEmitted ||
MI != LastFunctionOpVariable)
2257 assert(CurrentMAI &&
"CurrentMAI must be set");
2258 tryEmitDebugFunctionDefinition(*CurrentMAI);
2263 if (!GlobalNSDIEnabled || DebugFunctionDefinitionEmitted || !CurrentMF)
2266 assert(CurrentMF == &MF &&
2267 "notification does not match the current MachineFunction");
2269 if (LastFunctionOpVariable)
2275 tryEmitDebugFunctionDefinition(*CurrentMAI);
2286 if (
MI.isDebugValueLike())
2291void SPIRVNonSemanticDebugHandler::collectDebugExpressions(
2293 MachineModuleInfo *ModuleInfo =
Asm->MMI;
2294 assert(ModuleInfo &&
"MachineModuleInfo must be set during module output");
2297 Out.insert(
MI.getDebugExpression());
2303 if (GlobalDIEmitted)
2306 GlobalDIEmitted =
true;
2308 if (CompileUnits.empty()) {
2309 GlobalNSDIEnabled =
false;
2315 if (!ExtInstSetReg.
isValid()) {
2316 GlobalNSDIEnabled =
false;
2321 assert(NonSemanticOpStringsSectionEmitted &&
2322 "emitNonSemanticDebugStrings() must run before "
2323 "emitNonSemanticGlobalDebugInfo()");
2328 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
2329 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
2331 CachedDebugInfoNoneReg = emitExtInst(SPIRV::NonSemanticExtInst::DebugInfoNone,
2332 VoidTypeReg, ExtInstSetReg, {}, MAI);
2344 MCRegister DebugInfoVersionReg = emitOpConstantI32(100, I32TypeReg, MAI);
2346 emitOpConstantI32(
static_cast<uint32_t>(DwarfVersion), I32TypeReg, MAI);
2351 map_to_vector(CompileUnits, [&](
const CompileUnitInfo &Info) {
2352 return emitOpConstantI32(Info.SpirvSourceLanguage, I32TypeReg, MAI);
2356 for (
auto [Info, SrcLangReg] :
llvm::zip(CompileUnits, SrcLangRegs)) {
2357 MCRegister FileStrReg = ScopeToPathOpStringReg.lookup(Info.TheCU);
2359 "CU path OpString must be emitted in emitNonSemanticDebugStrings");
2360 MCRegister DebugSourceReg = getOrEmitDebugSourceForFileStrReg(
2361 FileStrReg, VoidTypeReg, ExtInstSetReg, MAI);
2363 SPIRV::NonSemanticExtInst::DebugCompilationUnit, VoidTypeReg,
2365 {DebugInfoVersionReg, DwarfVersionReg, DebugSourceReg, SrcLangReg},
2368 DebugScopeRegs[Info.TheCU] = CUDbgReg;
2373 getOrCreateDebugScope(S);
2378 if (
auto LVReg = emitDebugLocalVariable(LV, VoidTypeReg, I32TypeReg,
2379 ExtInstSetReg, MAI))
2380 DebugLocalVariableRegs[LV] = *LVReg;
2387 collectDebugExpressions(Expressions);
2389 if (
auto ExprReg = emitDebugExpression(Expr, VoidTypeReg, I32TypeReg,
2390 ExtInstSetReg, MAI))
2391 DebugExpressionRegs[Expr] = *ExprReg;
2394 for (
const auto &[GV, Info] : GlobalVariableDebugInfoMap)
2395 emitDebugGlobalVariable(GV, Info, VoidTypeReg, I32TypeReg, ExtInstSetReg,
2401 getOrEmitDebugInlinedAt(IA, VoidTypeReg, I32TypeReg, ExtInstSetReg, MAI);
2406 assert(ModuleInfo &&
"MachineModuleInfo must be set during module output");
2408 std::optional<std::pair<const DIBasicType *, uint64_t>> Const =
2412 if (!DebugLocalVariableRegs.contains(
MI.getDebugVariable()) ||
2413 !DebugExpressionRegs.contains(
MI.getDebugExpression()))
2415 auto [It, Inserted] = ConstantValueRegs.try_emplace(*Const,
MCRegister());
2417 It->second = findOrEmitScalarConstant(Const->first, Const->second, MAI);
2418 if (!It->second.isValid())
2419 ConstantValueRegs.erase(It);
2423 emitOpConstantI32(
DL->getLine(), I32TypeReg, MAI);
2424 emitOpConstantI32(
DL->getColumn(), I32TypeReg, MAI);
2425 emitOpConstantI32(
DL->getColumn() + 1, I32TypeReg, MAI);
2427 getCachedScopePathOpStringReg(
DL->getScope(),
2429 getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg, ExtInstSetReg,
2433 GlobalNSDIEnabled =
true;
2437SPIRVNonSemanticDebugHandler::getDebugFullPath(
const DIScope *Scope)
const {
2447 Out.assign(Dir.
begin(), Dir.
end());
2453MCRegister SPIRVNonSemanticDebugHandler::getOrEmitDebugSourceForFileStrReg(
2456 const unsigned Key = FileStrReg.
id();
2457 auto It = DebugSourceRegByFileStr.find(
Key);
2458 if (It != DebugSourceRegByFileStr.end())
2461 MCRegister
DS = emitExtInst(SPIRV::NonSemanticExtInst::DebugSource,
2462 VoidTypeReg, ExtInstSetReg, {FileStrReg}, MAI);
2463 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)