-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Store the type parameters of bound generics in the debug info. #31118
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -92,6 +92,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { | |
llvm::DenseMap<const void *, llvm::TrackingMDNodeRef> DIModuleCache; | ||
llvm::StringMap<llvm::TrackingMDNodeRef> DIFileCache; | ||
TrackingDIRefMap DIRefMap; | ||
TrackingDIRefMap InnerTypeCache; | ||
/// @} | ||
|
||
/// A list of replaceable fwddecls that need to be RAUWed at the end. | ||
|
@@ -765,7 +766,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { | |
} | ||
|
||
StringRef getMangledName(DebugTypeInfo DbgTy) { | ||
if (DbgTy.IsMetadataType) | ||
if (DbgTy.isMetadataType()) | ||
return MetadataTypeDeclCache.find(DbgTy.getDecl()->getName().str()) | ||
->getKey(); | ||
|
||
|
@@ -829,12 +830,12 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { | |
llvm::DINode::DIFlags Flags) { | ||
unsigned SizeOfByte = CI.getTargetInfo().getCharWidth(); | ||
auto *Ty = getOrCreateType(DbgTy); | ||
auto *DITy = DBuilder.createMemberType(Scope, Name, File, 0, | ||
SizeOfByte * DbgTy.size.getValue(), | ||
0, OffsetInBits, Flags, Ty); | ||
auto *DITy = DBuilder.createMemberType( | ||
Scope, Name, File, 0, SizeOfByte * DbgTy.getSize().getValue(), 0, | ||
OffsetInBits, Flags, Ty); | ||
OffsetInBits += getSizeInBits(Ty); | ||
OffsetInBits = | ||
llvm::alignTo(OffsetInBits, SizeOfByte * DbgTy.align.getValue()); | ||
OffsetInBits = llvm::alignTo(OffsetInBits, | ||
SizeOfByte * DbgTy.getAlignment().getValue()); | ||
return DITy; | ||
} | ||
|
||
|
@@ -929,8 +930,9 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { | |
// one of the raw type as long as it is large enough to hold | ||
// all enum values. Use the raw type for the debug type, but | ||
// the storage size from the enum. | ||
ElemDbgTy = DebugTypeInfo(ED->getRawType(), DbgTy.StorageType, | ||
DbgTy.size, DbgTy.align, true, false); | ||
ElemDbgTy = | ||
DebugTypeInfo(ED->getRawType(), DbgTy.getStorageType(), | ||
DbgTy.getSize(), DbgTy.getAlignment(), true, false); | ||
else if (auto ArgTy = ElemDecl->getArgumentInterfaceType()) { | ||
// A discriminated union. This should really be described as a | ||
// DW_TAG_variant_type. For now only describing the data. | ||
|
@@ -941,12 +943,13 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { | |
// Discriminated union case without argument. Fallback to Int | ||
// as the element type; there is no storage here. | ||
Type IntTy = IGM.Context.getIntDecl()->getDeclaredType(); | ||
ElemDbgTy = DebugTypeInfo(IntTy, DbgTy.StorageType, Size(0), | ||
ElemDbgTy = DebugTypeInfo(IntTy, DbgTy.getStorageType(), Size(0), | ||
Alignment(1), true, false); | ||
} | ||
unsigned Offset = 0; | ||
auto MTy = createMemberType(ElemDbgTy, ElemDecl->getBaseIdentifier().str(), | ||
Offset, Scope, File, Flags); | ||
auto MTy = | ||
createMemberType(ElemDbgTy, ElemDecl->getBaseIdentifier().str(), | ||
Offset, Scope, File, Flags); | ||
Elements.push_back(MTy); | ||
} | ||
return DBuilder.getOrCreateArray(Elements); | ||
|
@@ -958,7 +961,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { | |
llvm::DIFile *File, unsigned Line, | ||
llvm::DINode::DIFlags Flags) { | ||
unsigned SizeOfByte = CI.getTargetInfo().getCharWidth(); | ||
unsigned SizeInBits = DbgTy.size.getValue() * SizeOfByte; | ||
unsigned SizeInBits = DbgTy.getSize().getValue() * SizeOfByte; | ||
// Default, since Swift doesn't allow specifying a custom alignment. | ||
unsigned AlignInBits = 0; | ||
|
||
|
@@ -982,16 +985,17 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { | |
} | ||
|
||
llvm::DIType *getOrCreateDesugaredType(Type Ty, DebugTypeInfo DbgTy) { | ||
DebugTypeInfo BlandDbgTy(Ty, DbgTy.StorageType, DbgTy.size, DbgTy.align, | ||
DbgTy.DefaultAlignment, DbgTy.IsMetadataType); | ||
DebugTypeInfo BlandDbgTy(Ty, DbgTy.getStorageType(), DbgTy.getSize(), | ||
DbgTy.getAlignment(), DbgTy.hasDefaultAlignment(), | ||
DbgTy.isMetadataType()); | ||
return getOrCreateType(BlandDbgTy); | ||
} | ||
|
||
uint64_t getSizeOfBasicType(DebugTypeInfo DbgTy) { | ||
uint64_t SizeOfByte = CI.getTargetInfo().getCharWidth(); | ||
uint64_t BitWidth = DbgTy.size.getValue() * SizeOfByte; | ||
llvm::Type *StorageType = DbgTy.StorageType | ||
? DbgTy.StorageType | ||
uint64_t BitWidth = DbgTy.getSize().getValue() * SizeOfByte; | ||
llvm::Type *StorageType = DbgTy.getStorageType() | ||
? DbgTy.getStorageType() | ||
: IGM.DataLayout.getSmallestLegalIntType( | ||
IGM.getLLVMContext(), BitWidth); | ||
|
||
|
@@ -1003,23 +1007,44 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { | |
return BitWidth; | ||
} | ||
|
||
/// Collect the type parameters of a bound generic type. This is needed to | ||
/// anchor any typedefs that may appear in parameters so they can be | ||
/// resolved in the debugger without needing to query the Swift module. | ||
llvm::DINodeArray collectGenericParams(BoundGenericType *BGT) { | ||
SmallVector<llvm::Metadata *, 16> TemplateParams; | ||
for (auto Param : BGT->getGenericArgs()) { | ||
TemplateParams.push_back(DBuilder.createTemplateTypeParameter( | ||
TheCU, "", getOrCreateType(DebugTypeInfo::getForwardDecl(Param)))); | ||
Comment on lines
+1016
to
+1017
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On What's the right value to pass there to fix the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No worries. Thanks for the confirmation. :-) |
||
} | ||
return DBuilder.getOrCreateArray(TemplateParams); | ||
} | ||
|
||
/// Create a sized container for a sizeless type. Used to represent | ||
/// BoundGenericEnums that may have different sizes depending on what they are | ||
/// bound to, but still share a mangled name. | ||
llvm::DIType *createOpaqueStructWithSizedContainer( | ||
llvm::DIScope *Scope, StringRef Name, llvm::DIFile *File, unsigned Line, | ||
unsigned SizeInBits, unsigned AlignInBits, llvm::DINode::DIFlags Flags, | ||
StringRef MangledName) { | ||
// Let the MDNode folding set do the work of uniquing the inner type. This | ||
// should be cheap. | ||
llvm::DICompositeType *UniqueType = DBuilder.createStructType( | ||
Scope, Name, File, Line, 0, 0, Flags, nullptr, | ||
DBuilder.getOrCreateArray(ArrayRef<llvm::Metadata *>()), | ||
llvm::dwarf::DW_LANG_Swift, nullptr, MangledName); | ||
StringRef MangledName, llvm::DINodeArray BoundParams) { | ||
// This uses a separate cache and not DIRefMap for the inner type to avoid | ||
// associating the anonymous container (which is specific to the | ||
// variable/storage and not the type) with the MangledName. | ||
llvm::DICompositeType *UniqueType = nullptr; | ||
auto *UID = llvm::MDString::get(IGM.getLLVMContext(), MangledName); | ||
if (llvm::Metadata *V = InnerTypeCache.lookup(UID)) | ||
UniqueType = cast<llvm::DICompositeType>(V); | ||
else { | ||
UniqueType = DBuilder.createStructType( | ||
Scope, Name, File, Line, 0, 0, Flags, nullptr, nullptr, | ||
llvm::dwarf::DW_LANG_Swift, nullptr, MangledName); | ||
if (BoundParams) | ||
DBuilder.replaceArrays(UniqueType, nullptr, BoundParams); | ||
InnerTypeCache[UID] = llvm::TrackingMDNodeRef(UniqueType); | ||
} | ||
|
||
llvm::Metadata *Elements[] = { | ||
DBuilder.createMemberType(Scope, "", File, 0, SizeInBits, | ||
AlignInBits, 0, Flags, UniqueType)}; | ||
|
||
return DBuilder.createStructType( | ||
Scope, "", File, Line, SizeInBits, AlignInBits, Flags, | ||
/* DerivedFrom */ nullptr, DBuilder.getOrCreateArray(Elements), | ||
|
@@ -1188,9 +1213,10 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { | |
// emitting the storage size of the struct, but it may be necessary | ||
// to emit the (target!) size of the underlying basic type. | ||
uint64_t SizeOfByte = CI.getTargetInfo().getCharWidth(); | ||
uint64_t SizeInBits = DbgTy.size.getValue() * SizeOfByte; | ||
unsigned AlignInBits = | ||
DbgTy.DefaultAlignment ? 0 : DbgTy.align.getValue() * SizeOfByte; | ||
uint64_t SizeInBits = DbgTy.getSize().getValue() * SizeOfByte; | ||
unsigned AlignInBits = DbgTy.hasDefaultAlignment() | ||
? 0 | ||
: DbgTy.getAlignment().getValue() * SizeOfByte; | ||
unsigned Encoding = 0; | ||
llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; | ||
|
||
|
@@ -1332,7 +1358,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { | |
auto L = getDebugLoc(*this, Decl); | ||
return createOpaqueStructWithSizedContainer( | ||
Scope, Decl ? Decl->getNameStr() : "", File, L.Line, SizeInBits, | ||
AlignInBits, Flags, MangledName); | ||
AlignInBits, Flags, MangledName, collectGenericParams(StructTy)); | ||
} | ||
|
||
case TypeKind::BoundGenericClass: { | ||
|
@@ -1441,7 +1467,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { | |
auto *File = getOrCreateFile(L.Filename); | ||
return createOpaqueStructWithSizedContainer( | ||
Scope, Decl->getName().str(), File, L.Line, SizeInBits, AlignInBits, | ||
Flags, MangledName); | ||
Flags, MangledName, collectGenericParams(EnumTy)); | ||
} | ||
|
||
case TypeKind::BuiltinVector: { | ||
|
@@ -1480,9 +1506,9 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { | |
auto File = getOrCreateFile(L.Filename); | ||
// For TypeAlias types, the DeclContext for the aliased type is | ||
// in the decl of the alias type. | ||
DebugTypeInfo AliasedDbgTy(AliasedTy, DbgTy.StorageType, DbgTy.size, | ||
DbgTy.align, DbgTy.DefaultAlignment, | ||
false); | ||
DebugTypeInfo AliasedDbgTy(AliasedTy, DbgTy.getStorageType(), | ||
DbgTy.getSize(), DbgTy.getAlignment(), | ||
DbgTy.hasDefaultAlignment(), false); | ||
return DBuilder.createTypedef(getOrCreateType(AliasedDbgTy), MangledName, | ||
File, L.Line, Scope); | ||
} | ||
|
@@ -1637,8 +1663,24 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { | |
if (Decl->isOutermostPrivateOrFilePrivateScope()) | ||
Scope = getFilePrivateScope(Scope, Decl); | ||
|
||
// If this is a forward decl, create one for this mangled name and don't | ||
// cache it. | ||
if (DbgTy.isForwardDecl() && !isa<TypeAliasType>(DbgTy.getType())) { | ||
auto *FwdDecl = DBuilder.createReplaceableCompositeType( | ||
llvm::dwarf::DW_TAG_structure_type, MangledName, Scope, 0, 0, | ||
llvm::dwarf::DW_LANG_Swift, 0, 0, llvm::DINode::FlagFwdDecl, | ||
MangledName); | ||
ReplaceMap.emplace_back( | ||
std::piecewise_construct, std::make_tuple(DbgTy.getType()), | ||
std::make_tuple(static_cast<llvm::Metadata *>(FwdDecl))); | ||
return FwdDecl; | ||
} | ||
llvm::DIType *DITy = createType(DbgTy, MangledName, Scope, getFile(Scope)); | ||
|
||
// Don't cache a type alias to a forward declaration either. | ||
if (DbgTy.isForwardDecl()) | ||
return DITy; | ||
|
||
// Incrementally build the DIRefMap. | ||
if (auto *CTy = dyn_cast<llvm::DICompositeType>(DITy)) { | ||
#ifndef NDEBUG | ||
|
@@ -2178,11 +2220,11 @@ void IRGenDebugInfoImpl::emitVariableDeclaration( | |
return; | ||
|
||
// We cannot yet represent opened existentials. | ||
if (DbgTy.Type->hasOpenedExistential()) | ||
if (DbgTy.getType()->hasOpenedExistential()) | ||
return; | ||
|
||
if (!DbgTy.size) | ||
DbgTy.size = getStorageSize(IGM.DataLayout, Storage); | ||
if (!DbgTy.getSize()) | ||
DbgTy.setSize(getStorageSize(IGM.DataLayout, Storage)); | ||
|
||
auto *Scope = dyn_cast_or_null<llvm::DILocalScope>(getOrCreateScope(DS)); | ||
assert(Scope && "variable has no local scope"); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// RUN: %target-swift-frontend %s -O -emit-ir -g -o - | %FileCheck %s | ||
public struct S<T> { | ||
let t : T | ||
} | ||
|
||
public let s = S<Int>(t: 0) | ||
|
||
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "S", | ||
// CHECK-SAME: templateParams: ![[PARAMS:[0-9]+]], identifier: | ||
// CHECK: ![[PARAMS]] = !{![[INTPARAM:[0-9]+]]} | ||
// CHECK: ![[INTPARAM]] = !DITemplateTypeParameter(type: ![[INT:[0-9]+]]) | ||
// CHECK: ![[INT]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Int", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wdyt of making
StorageType
private in DebugTypeInfo and add a getter for it? This could assert if the field is null and the size is known?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in the second commit.