Skip to content

Commit 1e50aa5

Browse files
committed
[DebugInfo] Emit full DWARF info for generic classes and enums
1 parent b42752a commit 1e50aa5

File tree

1 file changed

+189
-70
lines changed

1 file changed

+189
-70
lines changed

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 189 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,9 +1066,6 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
10661066
for (VarDecl *VD : Decl->getStoredProperties()) {
10671067
auto memberTy = BaseTy->getTypeOfMember(IGM.getSwiftModule(), VD);
10681068

1069-
auto &TI = IGM.getTypeInfoForUnlowered(
1070-
IGM.getSILTypes().getAbstractionPattern(VD), memberTy);
1071-
10721069
if (auto DbgTy = CompletedDebugTypeInfo::getFromTypeInfo(
10731070
VD->getInterfaceType(),
10741071
IGM.getTypeInfoForUnlowered(
@@ -1090,14 +1087,14 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
10901087
return DITy;
10911088
}
10921089

1093-
/// Creates debug info for a generic struct with archetypes (e.g.:
1090+
/// Creates debug info for a generic struct or class with archetypes (e.g.:
10941091
/// Pair<τ_0_0, τ_0_1>). For types with unsubstituted generic type parameters,
10951092
/// debug info generation doesn't attempt to emit the size and aligment of
10961093
/// the type, as in the general case those are all dependent on substituting
10971094
/// the type parameters in (some exceptions exist, like generic types that are
10981095
/// class constrained). It also doesn't attempt to emit the offset of the
10991096
/// members for the same reason.
1100-
llvm::DICompositeType *createUnsubstitutedGenericStructType(
1097+
llvm::DICompositeType *createUnsubstitutedGenericStructOrClassType(
11011098
DebugTypeInfo DbgTy, NominalTypeDecl *Decl, Type UnsubstitutedType,
11021099
llvm::DIScope *Scope, llvm::DIFile *File, unsigned Line,
11031100
unsigned SizeInBits, unsigned AlignInBits, llvm::DINode::DIFlags Flags,
@@ -1129,7 +1126,69 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
11291126
Scope, Name, File, Line, SizeInBits, AlignInBits, Flags, DerivedFrom,
11301127
DBuilder.getOrCreateArray(Elements), RuntimeLang, nullptr, UniqueID);
11311128
DBuilder.replaceTemporary(std::move(FwdDecl), DITy);
1132-
return DITy;
1129+
return DITy;;
1130+
}
1131+
1132+
llvm::DIType *createFullDebugInfoGenericForStructOrClassType(
1133+
BoundGenericType *Type, NominalTypeDecl *Decl, llvm::DIScope *Scope,
1134+
llvm::DIFile *File, unsigned Line, unsigned SizeInBits,
1135+
unsigned AlignInBits, llvm::DINode::DIFlags Flags,
1136+
StringRef MangledName, bool IsClass = false) {
1137+
// To emit full debug info for generic types, the strategy is to emit
1138+
// full debug info for the type with archetypes, and still emit opaque
1139+
// debug information for the specialized type. For example, given:
1140+
// struct Pair<T, U> {
1141+
// let t : T
1142+
// let u: U
1143+
// }
1144+
// When emitting debug information for a type such as Pair<Int, Double>,
1145+
// emit full debug info for Pair<T, U>, and emit the regular debug
1146+
// information for Pair<Int, Double>.
1147+
1148+
// Go from Pair<Int, Double> to Pair<T, U>.
1149+
auto UnsubstitutedTy = Decl->getDeclaredInterfaceType();
1150+
UnsubstitutedTy = Decl->mapTypeIntoContext(UnsubstitutedTy);
1151+
1152+
auto DbgTy = DebugTypeInfo::getFromTypeInfo(
1153+
UnsubstitutedTy, IGM.getTypeInfoForUnlowered(UnsubstitutedTy), IGM,
1154+
false);
1155+
Mangle::ASTMangler Mangler;
1156+
std::string DeclTypeMangledName = Mangler.mangleTypeForDebugger(
1157+
UnsubstitutedTy->mapTypeOutOfContext(), {});
1158+
if (DeclTypeMangledName == MangledName) {
1159+
return createUnsubstitutedGenericStructOrClassType(
1160+
DbgTy, Decl, UnsubstitutedTy, Scope, File, Line, SizeInBits,
1161+
AlignInBits, Flags, nullptr, llvm::dwarf::DW_LANG_Swift,
1162+
DeclTypeMangledName);
1163+
}
1164+
// Force the creation of the unsubstituted type, don't create it
1165+
// directly so it goes through all the caching/verification logic.
1166+
auto UnsubstitutedType = getOrCreateType(DbgTy);
1167+
1168+
if (auto *ClassTy = llvm::dyn_cast<BoundGenericClassType>(Type)) {
1169+
auto SuperClassTy = ClassTy->getSuperclass();
1170+
if (SuperClassTy) {
1171+
auto SuperClassDbgTy = DebugTypeInfo::getFromTypeInfo(
1172+
SuperClassTy, IGM.getTypeInfoForUnlowered(SuperClassTy), IGM,
1173+
false);
1174+
1175+
llvm::DIType *SuperClassDITy = getOrCreateType(SuperClassDbgTy);
1176+
assert(SuperClassDITy && "getOrCreateType should never return null!");
1177+
DBuilder.createInheritance(UnsubstitutedType, SuperClassDITy, 0, 0,
1178+
llvm::DINode::FlagZero);
1179+
}
1180+
1181+
auto *OpaqueType = createPointerSizedStruct(
1182+
Scope, Decl ? Decl->getNameStr() : MangledName, File, 0, Flags,
1183+
MangledName, UnsubstitutedType);
1184+
return OpaqueType;
1185+
}
1186+
1187+
auto *opaqueType = createOpaqueStructWithSizedContainer(
1188+
Scope, Decl ? Decl->getNameStr() : "", File, Line, SizeInBits,
1189+
AlignInBits, Flags, MangledName, collectGenericParams(Type),
1190+
UnsubstitutedType);
1191+
return opaqueType;
11331192
}
11341193

11351194
/// Create debug information for an enum with a raw type (enum E : Int {}).
@@ -1185,7 +1244,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
11851244
return DITy;
11861245
}
11871246

1188-
// Create debug information for an enum with no raw type.
1247+
/// Create debug information for an enum with no raw type.
11891248
llvm::DICompositeType *createVariantType(CompletedDebugTypeInfo DbgTy,
11901249
EnumDecl *Decl,
11911250
StringRef MangledName,
@@ -1198,7 +1257,6 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
11981257

11991258
StringRef Name = Decl->getName().str();
12001259
unsigned SizeInBits = DbgTy.getSizeInBits();
1201-
// Default, since Swift doesn't allow specifying a custom alignment.
12021260
auto NumExtraInhabitants = DbgTy.getNumExtraInhabitants();
12031261

12041262
// A variant part should actually be a child to a DW_TAG_structure_type
@@ -1258,7 +1316,64 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
12581316
auto DITy = DBuilder.createStructType(
12591317
Scope, Name, File, Line, SizeInBits, AlignInBits, Flags, nullptr,
12601318
DBuilder.getOrCreateArray(VPTy), llvm::dwarf::DW_LANG_Swift, nullptr,
1261-
MangledName, NumExtraInhabitants.value_or(0));
1319+
MangledName, nullptr, NumExtraInhabitants ? *NumExtraInhabitants : 0);
1320+
DBuilder.replaceTemporary(std::move(FwdDecl), DITy);
1321+
return DITy;
1322+
}
1323+
1324+
// Create debug information for an enum with no raw type.
1325+
llvm::DICompositeType *
1326+
createUnsubstitutedVariantType(DebugTypeInfo DbgTy, EnumDecl *Decl,
1327+
StringRef MangledName, unsigned AlignInBits,
1328+
llvm::DIScope *Scope, llvm::DIFile *File,
1329+
unsigned Line, llvm::DINode::DIFlags Flags) {
1330+
assert(!Decl->getRawType() &&
1331+
"Attempting to create variant debug info from raw enum!");
1332+
1333+
StringRef Name = Decl->getName().str();
1334+
unsigned SizeInBits = DbgTy.getRawSizeInBits().value_or(0);
1335+
auto NumExtraInhabitants = DbgTy.getNumExtraInhabitants();
1336+
1337+
// A variant part should actually be a child to a DW_TAG_structure_type
1338+
// according to the DWARF spec.
1339+
auto FwdDecl = llvm::TempDIType(DBuilder.createReplaceableCompositeType(
1340+
llvm::dwarf::DW_TAG_structure_type, MangledName, Scope, File, Line,
1341+
llvm::dwarf::DW_LANG_Swift, SizeInBits, AlignInBits, Flags,
1342+
MangledName));
1343+
1344+
auto TH = llvm::TrackingMDNodeRef(FwdDecl.get());
1345+
DITypeCache[DbgTy.getType()] = TH;
1346+
1347+
SmallVector<llvm::Metadata *, 16> Elements;
1348+
for (auto *ElemDecl : Decl->getAllElements()) {
1349+
llvm::Optional<DebugTypeInfo> ElemDbgTy;
1350+
if (auto ArgTy = ElemDecl->getArgumentInterfaceType()) {
1351+
// A variant case which carries a payload.
1352+
ArgTy = ElemDecl->getParentEnum()->mapTypeIntoContext(ArgTy);
1353+
ElemDbgTy = DebugTypeInfo::getFromTypeInfo(
1354+
ArgTy, IGM.getTypeInfoForUnlowered(ArgTy), IGM, false);
1355+
unsigned Offset = 0;
1356+
auto MTy =
1357+
createMemberType(*ElemDbgTy, ElemDecl->getBaseIdentifier().str(),
1358+
Offset, Scope, File, Flags);
1359+
Elements.push_back(MTy);
1360+
} else {
1361+
// A variant with no payload.
1362+
auto MTy = DBuilder.createMemberType(
1363+
Scope, ElemDecl->getBaseIdentifier().str(), File, 0, 0, 0, 0, Flags,
1364+
nullptr);
1365+
Elements.push_back(MTy);
1366+
}
1367+
}
1368+
1369+
auto VPTy = DBuilder.createVariantPart(Scope, {}, File, Line, SizeInBits,
1370+
AlignInBits, Flags, nullptr,
1371+
DBuilder.getOrCreateArray(Elements));
1372+
1373+
auto DITy = DBuilder.createStructType(
1374+
Scope, Name, File, Line, SizeInBits, AlignInBits, Flags, nullptr,
1375+
DBuilder.getOrCreateArray(VPTy), llvm::dwarf::DW_LANG_Swift, nullptr,
1376+
MangledName, nullptr, NumExtraInhabitants.value_or(0));
12621377
DBuilder.replaceTemporary(std::move(FwdDecl), DITy);
12631378
return DITy;
12641379
}
@@ -1306,9 +1421,17 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
13061421
llvm::DINodeArray collectGenericParams(BoundGenericType *BGT) {
13071422
SmallVector<llvm::Metadata *, 16> TemplateParams;
13081423
for (auto Param : BGT->getGenericArgs()) {
1424+
DebugTypeInfo ParamDebugType;
1425+
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes)
1426+
// For full debug info don't generate just a forward declaration for
1427+
// the generic type parameters.
1428+
ParamDebugType = DebugTypeInfo::getFromTypeInfo(
1429+
Param, IGM.getTypeInfoForUnlowered(Param), IGM, false);
1430+
else
1431+
ParamDebugType = DebugTypeInfo::getForwardDecl(Param);
1432+
13091433
TemplateParams.push_back(DBuilder.createTemplateTypeParameter(
1310-
TheCU, "", getOrCreateType(DebugTypeInfo::getForwardDecl(Param)),
1311-
false));
1434+
TheCU, "", getOrCreateType(ParamDebugType), false));
13121435
}
13131436
return DBuilder.getOrCreateArray(TemplateParams);
13141437
}
@@ -1319,7 +1442,8 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
13191442
llvm::DIType *createOpaqueStructWithSizedContainer(
13201443
llvm::DIScope *Scope, StringRef Name, llvm::DIFile *File, unsigned Line,
13211444
unsigned SizeInBits, unsigned AlignInBits, llvm::DINode::DIFlags Flags,
1322-
StringRef MangledName, llvm::DINodeArray BoundParams) {
1445+
StringRef MangledName, llvm::DINodeArray BoundParams,
1446+
llvm::DIType *SpecificationOf = nullptr) {
13231447
// This uses a separate cache and not DIRefMap for the inner type to avoid
13241448
// associating the anonymous container (which is specific to the
13251449
// variable/storage and not the type) with the MangledName.
@@ -1341,39 +1465,40 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
13411465
return DBuilder.createStructType(
13421466
Scope, "", File, Line, SizeInBits, AlignInBits, Flags,
13431467
/* DerivedFrom */ nullptr, DBuilder.getOrCreateArray(Elements),
1344-
llvm::dwarf::DW_LANG_Swift);
1468+
llvm::dwarf::DW_LANG_Swift, nullptr, "", SpecificationOf, 0);
13451469
}
13461470

1347-
llvm::DIType *createPointerSizedStruct(llvm::DIScope *Scope, StringRef Name,
1348-
llvm::DIFile *File, unsigned Line,
1349-
llvm::DINode::DIFlags Flags,
1350-
StringRef MangledName) {
1471+
llvm::DIType *
1472+
createPointerSizedStruct(llvm::DIScope *Scope, StringRef Name,
1473+
llvm::DIFile *File, unsigned Line,
1474+
llvm::DINode::DIFlags Flags, StringRef MangledName,
1475+
llvm::DIType *SpecificationOf = nullptr) {
13511476
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes) {
13521477
auto FwdDecl = DBuilder.createForwardDecl(
13531478
llvm::dwarf::DW_TAG_structure_type, Name, Scope, File, Line,
13541479
llvm::dwarf::DW_LANG_Swift, 0, 0);
13551480
return createPointerSizedStruct(Scope, Name, FwdDecl, File, Line, Flags,
1356-
MangledName);
1481+
MangledName, SpecificationOf);
13571482
} else {
13581483
unsigned SizeInBits = CI.getTargetInfo().getPointerWidth(clang::LangAS::Default);
13591484
return createOpaqueStruct(Scope, Name, File, Line, SizeInBits, 0, Flags,
13601485
MangledName);
13611486
}
13621487
}
13631488

1364-
llvm::DIType *createPointerSizedStruct(llvm::DIScope *Scope, StringRef Name,
1365-
llvm::DIType *PointeeTy,
1366-
llvm::DIFile *File, unsigned Line,
1367-
llvm::DINode::DIFlags Flags,
1368-
StringRef MangledName) {
1369-
unsigned PtrSize = CI.getTargetInfo().getPointerWidth(clang::LangAS::Default);
1489+
llvm::DIType *createPointerSizedStruct(
1490+
llvm::DIScope *Scope, StringRef Name, llvm::DIType *PointeeTy,
1491+
llvm::DIFile *File, unsigned Line, llvm::DINode::DIFlags Flags,
1492+
StringRef MangledName, llvm::DIType *SpecificationOf = nullptr) {
1493+
unsigned PtrSize =
1494+
CI.getTargetInfo().getPointerWidth(clang::LangAS::Default);
13701495
auto PtrTy = DBuilder.createPointerType(PointeeTy, PtrSize, 0);
13711496
llvm::Metadata *Elements[] = {DBuilder.createMemberType(
13721497
Scope, "ptr", File, 0, PtrSize, 0, 0, Flags, PtrTy)};
13731498
return DBuilder.createStructType(
13741499
Scope, Name, File, Line, PtrSize, 0, Flags,
13751500
/* DerivedFrom */ nullptr, DBuilder.getOrCreateArray(Elements),
1376-
llvm::dwarf::DW_LANG_Swift, nullptr, MangledName);
1501+
llvm::dwarf::DW_LANG_Swift, nullptr, MangledName, SpecificationOf);
13771502
}
13781503

13791504
llvm::DIType *
@@ -1471,15 +1596,10 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
14711596
for (auto ElemTy : TupleTy->getElementTypes()) {
14721597
auto &elemTI = IGM.getTypeInfoForUnlowered(
14731598
AbstractionPattern(genericSig, ElemTy->getCanonicalType()), ElemTy);
1474-
if (auto DbgTy =
1475-
CompletedDebugTypeInfo::getFromTypeInfo(ElemTy, elemTI, IGM))
1599+
auto DbgTy =
1600+
DebugTypeInfo::getFromTypeInfo(ElemTy, elemTI, IGM, false);
14761601
Elements.push_back(
1477-
createMemberType(*DbgTy, "", OffsetInBits, Scope, MainFile, Flags));
1478-
else
1479-
// We can only create a forward declaration without complete size info.
1480-
return DBuilder.createReplaceableCompositeType(
1481-
llvm::dwarf::DW_TAG_structure_type, MangledName, Scope, MainFile, 0,
1482-
llvm::dwarf::DW_LANG_Swift, 0, AlignInBits, Flags, MangledName);
1602+
createMemberType(DbgTy, "", OffsetInBits, Scope, MainFile, Flags));
14831603
}
14841604
// FIXME: assert that SizeInBits == OffsetInBits.
14851605
SizeInBits = OffsetInBits;
@@ -1596,7 +1716,8 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
15961716
Flags |= llvm::DINode::FlagArtificial;
15971717
llvm::DICompositeType *PTy = DBuilder.createStructType(
15981718
Scope, MangledName, File, 0, PtrSize, 0, Flags, nullptr, nullptr,
1599-
llvm::dwarf::DW_LANG_Swift, nullptr, {}, NumExtraInhabitants);
1719+
llvm::dwarf::DW_LANG_Swift, nullptr, {}, nullptr,
1720+
NumExtraInhabitants);
16001721
return PTy;
16011722

16021723
}
@@ -1721,42 +1842,11 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
17211842
auto *Decl = StructTy->getDecl();
17221843
auto L = getFileAndLocation(Decl);
17231844
unsigned FwdDeclLine = 0;
1724-
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes) {
1725-
// To emit full debug info for generic types, the strategy is to emit
1726-
// full debug info for the type with archetypes, and still emit opaque
1727-
// debug information for the specialized type. For example, given:
1728-
// struct Pair<T, U> {
1729-
// let t : T
1730-
// let u: U
1731-
// }
1732-
// When emitting debug information for a type such as Pair<Int, Double>,
1733-
// emit full debug info for Pair<T, U>, and emit the regular debug
1734-
// information for Pair<Int, Double>.
1735-
1736-
// Go from Pair<Int, Double> to Pair<T, U>.
1737-
auto UnsubstitutedTy = Decl->getDeclaredInterfaceType();
1738-
UnsubstitutedTy = Decl->mapTypeIntoContext(UnsubstitutedTy);
1739-
1740-
auto DbgTy = DebugTypeInfo::getFromTypeInfo(
1741-
UnsubstitutedTy, IGM.getTypeInfoForUnlowered(UnsubstitutedTy), IGM,
1742-
false);
1743-
Mangle::ASTMangler Mangler;
1744-
std::string DeclTypeMangledName = Mangler.mangleTypeForDebugger(
1745-
UnsubstitutedTy->mapTypeOutOfContext(), {});
1746-
if (DeclTypeMangledName == MangledName) {
1747-
return createUnsubstitutedGenericStructType(
1748-
DbgTy, Decl, UnsubstitutedTy, Scope, File, FwdDeclLine,
1749-
SizeInBits, AlignInBits, Flags, nullptr, llvm::dwarf::DW_LANG_Swift,
1750-
DeclTypeMangledName);
1751-
}
1752-
// Force the creation of the unsubstituted type, don't create it
1753-
// directly so it goes through all the caching/verification logic.
1754-
DBuilder.retainType(getOrCreateType(DbgTy));
1755-
1756-
// Fallthrough and create the opaque struct. This way debug info will
1757-
// have an opaque entry for Pair<Int, Double> and a full entry for
1758-
// Pair<T, U>.
1759-
}
1845+
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes)
1846+
return createFullDebugInfoGenericForStructOrClassType(
1847+
StructTy, Decl, Scope, L.File, L.Line, SizeInBits, AlignInBits,
1848+
Flags, MangledName);
1849+
17601850
return createOpaqueStructWithSizedContainer(
17611851
Scope, Decl ? Decl->getNameStr() : "", L.File, FwdDeclLine,
17621852
SizeInBits, AlignInBits, Flags, MangledName,
@@ -1769,6 +1859,11 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
17691859
auto L = getFileAndLocation(Decl);
17701860
unsigned FwdDeclLine = 0;
17711861

1862+
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes)
1863+
return createFullDebugInfoGenericForStructOrClassType(
1864+
ClassTy, Decl, Scope, L.File, L.Line, SizeInBits, AlignInBits,
1865+
Flags, MangledName);
1866+
17721867
// TODO: We may want to peek at Decl->isObjC() and set this
17731868
// attribute accordingly.
17741869
assert(SizeInBits ==
@@ -1899,6 +1994,30 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
18991994
auto L = getFileAndLocation(Decl);
19001995
unsigned FwdDeclLine = 0;
19011996

1997+
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes) {
1998+
auto UnsubstitutedTy = Decl->getDeclaredInterfaceType();
1999+
UnsubstitutedTy = Decl->mapTypeIntoContext(UnsubstitutedTy);
2000+
2001+
auto DbgTy = DebugTypeInfo::getFromTypeInfo(
2002+
UnsubstitutedTy, IGM.getTypeInfoForUnlowered(UnsubstitutedTy), IGM,
2003+
false);
2004+
Mangle::ASTMangler Mangler;
2005+
std::string DeclTypeMangledName = Mangler.mangleTypeForDebugger(
2006+
UnsubstitutedTy->mapTypeOutOfContext(), {});
2007+
if (DeclTypeMangledName == MangledName) {
2008+
return createUnsubstitutedVariantType(DbgTy, Decl, MangledName,
2009+
AlignInBits, Scope, File, FwdDeclLine,
2010+
Flags);
2011+
}
2012+
// Force the creation of the unsubstituted type, don't create it
2013+
// directly so it goes through all the caching/verification logic.
2014+
auto unsubstitutedDbgTy = getOrCreateType(DbgTy);
2015+
DBuilder.retainType(unsubstitutedDbgTy);
2016+
return createOpaqueStructWithSizedContainer(
2017+
Scope, Decl->getName().str(), L.File, FwdDeclLine, SizeInBits,
2018+
AlignInBits, Flags, MangledName, collectGenericParams(EnumTy),
2019+
unsubstitutedDbgTy);
2020+
}
19022021
return createOpaqueStructWithSizedContainer(
19032022
Scope, Decl->getName().str(), L.File, FwdDeclLine, SizeInBits,
19042023
AlignInBits, Flags, MangledName, collectGenericParams(EnumTy));

0 commit comments

Comments
 (0)