Skip to content

Commit 1bf6375

Browse files
committed
[DebugInfo] Generate full debug info for generic structs
Generate the full debug info for generic structs. The strategy is to emit one full entry for the generic type with archetypes, and one forward declaration per instantiation of the generic type. For example, given: ``` struct Pair<T, U> { let t: T let u: U } let p1 = Pair<Int, Double>(t: 1, u: 4.2) let p2 = Pair<String, Bool>(t: "Hello", u: true) ``` DebugInfo will have one entry for Pair<T, U> which includes descriptions of its fields, one forward declaration of Pair<Int, Double> and one forward declaration of Pair<String, Bool>. This information is enough for the algorithms of RemoteMirrors to reconstruct type information for the fully instantiated types.
1 parent 1185730 commit 1bf6375

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)