Skip to content

Commit 0a99491

Browse files
authored
Merge pull request swiftlang#69902 from augusto2112/gen-generic-struct
[DebugInfo] Generate full debug info for generic structs
2 parents 21918f4 + 1bf6375 commit 0a99491

File tree

2 files changed

+131
-32
lines changed

2 files changed

+131
-32
lines changed

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 116 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,30 +1008,27 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
10081008
return BumpAllocatedString(Result);
10091009
}
10101010

1011-
llvm::DIDerivedType *createMemberType(CompletedDebugTypeInfo DbgTy,
1012-
StringRef Name, unsigned &OffsetInBits,
1011+
llvm::DIDerivedType *createMemberType(DebugTypeInfo DbgTy, StringRef Name,
1012+
unsigned &OffsetInBits,
10131013
llvm::DIScope *Scope,
10141014
llvm::DIFile *File,
10151015
llvm::DINode::DIFlags Flags) {
10161016
unsigned SizeOfByte = CI.getTargetInfo().getCharWidth();
10171017
auto *Ty = getOrCreateType(DbgTy);
1018-
auto *DITy =
1019-
DBuilder.createMemberType(Scope, Name, File, 0, DbgTy.getSizeInBits(),
1020-
0, OffsetInBits, Flags, Ty);
1018+
auto *DITy = DBuilder.createMemberType(
1019+
Scope, Name, File, 0,
1020+
DbgTy.getRawSizeInBits() ? *DbgTy.getRawSizeInBits() : 0, 0,
1021+
OffsetInBits, Flags, Ty);
10211022
OffsetInBits += getSizeInBits(Ty);
10221023
OffsetInBits = llvm::alignTo(OffsetInBits,
10231024
SizeOfByte * DbgTy.getAlignment().getValue());
10241025
return DITy;
10251026
}
10261027

1027-
llvm::DICompositeType *
1028-
createStructType(DebugTypeInfo DbgTy, NominalTypeDecl *Decl, Type BaseTy,
1029-
llvm::DIScope *Scope, llvm::DIFile *File, unsigned Line,
1030-
unsigned SizeInBits, unsigned AlignInBits,
1031-
llvm::DINode::DIFlags Flags, llvm::DIType *DerivedFrom,
1032-
unsigned RuntimeLang, StringRef UniqueID) {
1033-
StringRef Name = Decl->getName().str();
1034-
1028+
llvm::TempDIType createStructForwardDecl(
1029+
DebugTypeInfo DbgTy, NominalTypeDecl *Decl, llvm::DIScope *Scope,
1030+
llvm::DIFile *File, unsigned Line, unsigned SizeInBits,
1031+
llvm::DINode::DIFlags Flags, StringRef UniqueID, StringRef Name) {
10351032
// Forward declare this first because types may be recursive.
10361033
auto FwdDecl = llvm::TempDIType(DBuilder.createReplaceableCompositeType(
10371034
llvm::dwarf::DW_TAG_structure_type, Name, Scope, File, Line,
@@ -1049,6 +1046,18 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
10491046

10501047
auto TH = llvm::TrackingMDNodeRef(FwdDecl.get());
10511048
DITypeCache[DbgTy.getType()] = TH;
1049+
return FwdDecl;
1050+
}
1051+
1052+
llvm::DICompositeType *
1053+
createStructType(DebugTypeInfo DbgTy, NominalTypeDecl *Decl, Type BaseTy,
1054+
llvm::DIScope *Scope, llvm::DIFile *File, unsigned Line,
1055+
unsigned SizeInBits, unsigned AlignInBits,
1056+
llvm::DINode::DIFlags Flags, llvm::DIType *DerivedFrom,
1057+
unsigned RuntimeLang, StringRef UniqueID) {
1058+
StringRef Name = Decl->getName().str();
1059+
auto FwdDecl = createStructForwardDecl(DbgTy, Decl, Scope, File, Line,
1060+
SizeInBits, Flags, UniqueID, Name);
10521061
// Collect the members.
10531062
SmallVector<llvm::Metadata *, 16> Elements;
10541063
unsigned OffsetInBits = 0;
@@ -1078,6 +1087,48 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
10781087
return DITy;
10791088
}
10801089

1090+
/// Creates debug info for a generic struct with archetypes (e.g.:
1091+
/// Pair<τ_0_0, τ_0_1>). For types with unsubstituted generic type parameters,
1092+
/// debug info generation doesn't attempt to emit the size and aligment of
1093+
/// the type, as in the general case those are all dependent on substituting
1094+
/// the type parameters in (some exceptions exist, like generic types that are
1095+
/// class constrained). It also doesn't attempt to emit the offset of the
1096+
/// members for the same reason.
1097+
llvm::DICompositeType *createUnsubstitutedGenericStructType(
1098+
DebugTypeInfo DbgTy, NominalTypeDecl *Decl, Type UnsubstitutedType,
1099+
llvm::DIScope *Scope, llvm::DIFile *File, unsigned Line,
1100+
unsigned SizeInBits, unsigned AlignInBits, llvm::DINode::DIFlags Flags,
1101+
llvm::DIType *DerivedFrom, unsigned RuntimeLang, StringRef UniqueID) {
1102+
// FIXME: ideally, we'd like to emit this type with no size and alignment at
1103+
// all (instead of emitting them as 0). Fix this by changing DIBuilder to
1104+
// allow for struct types that have optional size and alignment.
1105+
StringRef Name = Decl->getName().str();
1106+
auto FwdDecl = createStructForwardDecl(DbgTy, Decl, Scope, File, Line,
1107+
SizeInBits, Flags, UniqueID, Name);
1108+
1109+
// Collect the members.
1110+
SmallVector<llvm::Metadata *, 16> Elements;
1111+
for (VarDecl *VD : Decl->getStoredProperties()) {
1112+
auto memberTy =
1113+
UnsubstitutedType->getTypeOfMember(IGM.getSwiftModule(), VD);
1114+
auto DbgTy = DebugTypeInfo::getFromTypeInfo(
1115+
memberTy,
1116+
IGM.getTypeInfoForUnlowered(
1117+
IGM.getSILTypes().getAbstractionPattern(VD), memberTy),
1118+
IGM, false);
1119+
unsigned OffsetInBits = 0;
1120+
llvm::DIType *DITy = createMemberType(DbgTy, VD->getName().str(),
1121+
OffsetInBits, Scope, File, Flags);
1122+
Elements.push_back(DITy);
1123+
}
1124+
1125+
auto DITy = DBuilder.createStructType(
1126+
Scope, Name, File, Line, SizeInBits, AlignInBits, Flags, DerivedFrom,
1127+
DBuilder.getOrCreateArray(Elements), RuntimeLang, nullptr, UniqueID);
1128+
DBuilder.replaceTemporary(std::move(FwdDecl), DITy);
1129+
return DITy;
1130+
}
1131+
10811132
/// Create debug information for an enum with a raw type (enum E : Int {}).
10821133
llvm::DICompositeType *createRawEnumType(CompletedDebugTypeInfo DbgTy,
10831134
EnumDecl *Decl,
@@ -1443,6 +1494,20 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
14431494
llvm::dwarf::DW_LANG_Swift, nullptr, MangledName);
14441495
}
14451496

1497+
bool shouldCacheDIType(llvm::DIType *DITy, DebugTypeInfo &DbgTy) {
1498+
// Don't cache a type alias to a forward declaration either.
1499+
if (DbgTy.isForwardDecl() || DbgTy.isFixedBuffer() ||
1500+
DITy->isForwardDecl())
1501+
return false;
1502+
1503+
if (auto Ty = DbgTy.getType())
1504+
// FIXME: Primary archetypes carry all sorts of auxiliary information
1505+
// that isn't contained in their mangled name. See also
1506+
// getMangledName().
1507+
return Ty->getKind() != swift::TypeKind::PrimaryArchetype;
1508+
return true;
1509+
}
1510+
14461511
llvm::DIType *createType(DebugTypeInfo DbgTy, StringRef MangledName,
14471512
llvm::DIScope *Scope, llvm::DIFile *File) {
14481513
// FIXME: For SizeInBits, clang uses the actual size of the type on
@@ -1640,6 +1705,42 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
16401705
auto *Decl = StructTy->getDecl();
16411706
auto L = getFileAndLocation(Decl);
16421707
unsigned FwdDeclLine = 0;
1708+
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes) {
1709+
// To emit full debug info for generic types, the strategy is to emit
1710+
// full debug info for the type with archetypes, and still emit opaque
1711+
// debug information for the specialized type. For example, given:
1712+
// struct Pair<T, U> {
1713+
// let t : T
1714+
// let u: U
1715+
// }
1716+
// When emitting debug information for a type such as Pair<Int, Double>,
1717+
// emit full debug info for Pair<T, U>, and emit the regular debug
1718+
// information for Pair<Int, Double>.
1719+
1720+
// Go from Pair<Int, Double> to Pair<T, U>.
1721+
auto UnsubstitutedTy = Decl->getDeclaredInterfaceType();
1722+
UnsubstitutedTy = Decl->mapTypeIntoContext(UnsubstitutedTy);
1723+
1724+
auto DbgTy = DebugTypeInfo::getFromTypeInfo(
1725+
UnsubstitutedTy, IGM.getTypeInfoForUnlowered(UnsubstitutedTy), IGM,
1726+
false);
1727+
Mangle::ASTMangler Mangler;
1728+
std::string DeclTypeMangledName = Mangler.mangleTypeForDebugger(
1729+
UnsubstitutedTy->mapTypeOutOfContext(), {});
1730+
if (DeclTypeMangledName == MangledName) {
1731+
return createUnsubstitutedGenericStructType(
1732+
DbgTy, Decl, UnsubstitutedTy, Scope, File, FwdDeclLine,
1733+
SizeInBits, AlignInBits, Flags, nullptr, llvm::dwarf::DW_LANG_Swift,
1734+
DeclTypeMangledName);
1735+
}
1736+
// Force the creation of the unsubstituted type, don't create it
1737+
// directly so it goes through all the caching/verification logic.
1738+
DBuilder.retainType(getOrCreateType(DbgTy));
1739+
1740+
// Fallthrough and create the opaque struct. This way debug info will
1741+
// have an opaque entry for Pair<Int, Double> and a full entry for
1742+
// Pair<T, U>.
1743+
}
16431744
return createOpaqueStructWithSizedContainer(
16441745
Scope, Decl ? Decl->getNameStr() : "", L.File, FwdDeclLine,
16451746
SizeInBits, AlignInBits, Flags, MangledName,
@@ -2026,26 +2127,9 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
20262127
}
20272128
llvm::DIType *DITy = createType(DbgTy, MangledName, Scope, getFile(Scope));
20282129

2029-
// Don't cache a type alias to a forward declaration either.
2030-
if (DbgTy.isForwardDecl() || DbgTy.isFixedBuffer() ||
2031-
DITy->isForwardDecl())
2032-
return DITy;
20332130

2034-
if (auto Ty = DbgTy.getType())
2035-
switch (Ty->getKind()) {
2036-
case TypeKind::PrimaryArchetype:
2037-
// FIXME: Primary archetypes carry all sorts of auxiliary information
2038-
// that isn't contained in their mangled name. See also
2039-
// getMangledName().
2040-
return DITy;
2041-
case TypeKind::BoundGenericEnum:
2042-
case TypeKind::BoundGenericStruct:
2043-
// FIXME: These are emitted in sized anonymous containers, and their
2044-
// size is not consistent when resilient.
2045-
return DITy;
2046-
default:
2047-
break;
2048-
}
2131+
if (!shouldCacheDIType(DITy, DbgTy))
2132+
return DITy;
20492133

20502134
// Incrementally build the DIRefMap.
20512135
if (auto *CTy = dyn_cast<llvm::DICompositeType>(DITy)) {

test/DebugInfo/BoundGenericStruct.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %target-swift-frontend %s -O -emit-ir -g -o - | %FileCheck %s
2+
// RUN: %target-swift-frontend %s -emit-ir -gdwarf-types -o - | %FileCheck %s --check-prefix=DWARF
23
public struct S<T> {
34
let t : T
45
}
@@ -10,3 +11,17 @@ public let s = S<Int>(t: 0)
1011
// CHECK: ![[PARAMS]] = !{![[INTPARAM:[0-9]+]]}
1112
// CHECK: ![[INTPARAM]] = !DITemplateTypeParameter(type: ![[INT:[0-9]+]])
1213
// CHECK: ![[INT]] = !DICompositeType(tag: DW_TAG_structure_type, name: "$sSiD",
14+
15+
16+
// DWARF: !DICompositeType(tag: DW_TAG_structure_type, name: "$s18BoundGenericStruct1SVySiGD",
17+
// DWARF-SAME: templateParams: ![[PARAMS:[0-9]+]]
18+
// DWARF: ![[PARAMS]] = !{![[INTPARAM:[0-9]+]]}
19+
// DWARF: ![[INTPARAM]] = !DITemplateTypeParameter(type: ![[INT:[0-9]+]])
20+
// DWARF: ![[INT]] = !DICompositeType(tag: DW_TAG_structure_type, name: "$sSiD",
21+
22+
// DWARF: !DICompositeType(tag: DW_TAG_structure_type, name: "S",
23+
// DWARF-SAME: identifier: "$s18BoundGenericStruct1SVyxGD")
24+
// DWARF: !DIDerivedType(tag: DW_TAG_member, name: "t"
25+
// DWARF: !DICompositeType(tag: DW_TAG_structure_type, name: "$sxD"
26+
27+

0 commit comments

Comments
 (0)