Add a completed/incomplete type difference. This allows us to have

partial types for contexts and forward decls while allowing us to
complete types later on for debug purposes.

This piggy-backs on the metadata replacement and rauw changes
for temporary nodes and takes advantage of the incremental
support I added in earlier. This allows us to, if we decide,
to limit adding methods and variables to structures in order
to limit the amount of debug information output into a .o file.

The caching is a bit complicated though so any thoughts on
untangling that are welcome.

llvm-svn: 150631
This commit is contained in:
Eric Christopher 2012-02-15 23:25:18 +00:00
parent 923d199a67
commit 7381907e65
3 changed files with 190 additions and 68 deletions

View File

@ -524,11 +524,8 @@ llvm::DIDescriptor CGDebugInfo::createContextChain(const Decl *Context) {
if (const RecordDecl *RD = dyn_cast<RecordDecl>(Context)) { if (const RecordDecl *RD = dyn_cast<RecordDecl>(Context)) {
if (!RD->isDependentType()) { if (!RD->isDependentType()) {
llvm::DIDescriptor FDContext = llvm::DIType Ty = getOrCreateLimitedType(CGM.getContext().getTypeDeclType(RD),
createContextChain(cast<Decl>(RD->getDeclContext())); getOrCreateMainFile());
llvm::DIType Ty = createRecordFwdDecl(RD, FDContext);
RegionMap[Context] = llvm::WeakVH(Ty);
return llvm::DIDescriptor(Ty); return llvm::DIDescriptor(Ty);
} }
} }
@ -557,7 +554,9 @@ llvm::DIType CGDebugInfo::CreatePointeeType(QualType PointeeTy,
RecordDecl *RD = RTy->getDecl(); RecordDecl *RD = RTy->getDecl();
llvm::DIDescriptor FDContext = llvm::DIDescriptor FDContext =
getContextDescriptor(cast<Decl>(RD->getDeclContext())); getContextDescriptor(cast<Decl>(RD->getDeclContext()));
return createRecordFwdDecl(RD, FDContext); llvm::DIType RetTy = createRecordFwdDecl(RD, FDContext);
TypeCache[PointeeTy.getAsOpaquePtr()] = RetTy;
return RetTy;
} }
return getOrCreateType(PointeeTy, Unit); return getOrCreateType(PointeeTy, Unit);
@ -654,10 +653,11 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, llvm::DIFile Unit) {
// declared. // declared.
unsigned Line = getLineNumber(Ty->getDecl()->getLocation()); unsigned Line = getLineNumber(Ty->getDecl()->getLocation());
const TypedefNameDecl *TyDecl = Ty->getDecl(); const TypedefNameDecl *TyDecl = Ty->getDecl();
llvm::DIDescriptor TypedefContext = llvm::DIDescriptor TypedefContext =
getContextDescriptor(cast<Decl>(Ty->getDecl()->getDeclContext())); getContextDescriptor(cast<Decl>(Ty->getDecl()->getDeclContext()));
return return
DBuilder.createTypedef(Src, TyDecl->getName(), Unit, Line, TypedefContext); DBuilder.createTypedef(Src, TyDecl->getName(), Unit, Line, TypedefContext);
} }
@ -1133,8 +1133,6 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
// Get overall information about the record type for the debug info. // Get overall information about the record type for the debug info.
llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation()); llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
unsigned Line = getLineNumber(RD->getLocation());
StringRef RDName = RD->getName();
// Records and classes and unions can all be recursive. To handle them, we // Records and classes and unions can all be recursive. To handle them, we
// first generate a debug descriptor for the struct as a forward declaration. // first generate a debug descriptor for the struct as a forward declaration.
@ -1143,28 +1141,21 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
// may refer to the forward decl if the struct is recursive) and replace all // may refer to the forward decl if the struct is recursive) and replace all
// uses of the forward declaration with the final definition. // uses of the forward declaration with the final definition.
llvm::DIDescriptor RDContext; llvm::DIType FwdDecl = getOrCreateLimitedType(QualType(Ty, 0), DefUnit);
if (CGM.getCodeGenOpts().LimitDebugInfo)
RDContext = createContextChain(cast<Decl>(RD->getDeclContext()));
else
RDContext = getContextDescriptor(cast<Decl>(RD->getDeclContext()));
// If this is just a forward declaration, construct an appropriately
// marked node and just return it.
if (!RD->getDefinition())
return createRecordFwdDecl(RD, RDContext);
llvm::DIType FwdDecl = DBuilder.createTemporaryType(DefUnit);
if (FwdDecl.isForwardDecl())
return FwdDecl;
llvm::MDNode *MN = FwdDecl; llvm::MDNode *MN = FwdDecl;
llvm::TrackingVH<llvm::MDNode> FwdDeclNode = MN; llvm::TrackingVH<llvm::MDNode> FwdDeclNode = MN;
// Otherwise, insert it into the TypeCache so that recursive uses will find
// it.
TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
// Push the struct on region stack. // Push the struct on region stack.
LexicalBlockStack.push_back(FwdDeclNode); LexicalBlockStack.push_back(FwdDeclNode);
RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl); RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
// Add this to the completed types cache since we're completing it.
CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
// Convert all the elements. // Convert all the elements.
SmallVector<llvm::Value *, 16> EltTys; SmallVector<llvm::Value *, 16> EltTys;
@ -1196,50 +1187,20 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
if (RI != RegionMap.end()) if (RI != RegionMap.end())
RegionMap.erase(RI); RegionMap.erase(RI);
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys); llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
llvm::MDNode *RealDecl = NULL; // FIXME: Magic numbers ahoy! These should be changed when we
// get some enums in llvm/Analysis/DebugInfo.h to refer to
// them.
if (RD->isUnion()) if (RD->isUnion())
RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line, MN->replaceOperandWith(10, Elements);
Size, Align, 0, Elements);
else if (CXXDecl) { else if (CXXDecl) {
RDName = getClassName(RD); MN->replaceOperandWith(10, Elements);
// A class's primary base or the class itself contains the vtable. MN->replaceOperandWith(13, TParamsArray);
llvm::MDNode *ContainingType = NULL;
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) {
// Seek non virtual primary base root.
while (1) {
const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase);
const CXXRecordDecl *PBT = BRL.getPrimaryBase();
if (PBT && !BRL.isPrimaryBaseVirtual())
PBase = PBT;
else
break;
}
ContainingType =
getOrCreateType(QualType(PBase->getTypeForDecl(), 0), DefUnit);
}
else if (CXXDecl->isDynamicClass())
ContainingType = FwdDecl;
// FIXME: This could be a struct type giving a default visibility different
// than C++ class type, but needs llvm metadata changes first.
RealDecl = DBuilder.createClassType(RDContext, RDName, DefUnit, Line,
Size, Align, 0, 0, llvm::DIType(),
Elements, ContainingType,
TParamsArray);
} else } else
RealDecl = DBuilder.createStructType(RDContext, RDName, DefUnit, Line, MN->replaceOperandWith(10, Elements);
Size, Align, 0, Elements);
// Now that we have a real decl for the struct, replace anything using the RegionMap[Ty->getDecl()] = llvm::WeakVH(MN);
// old decl with the new one. This will recursively update the debug info. return llvm::DIType(MN);
llvm::DIType(FwdDeclNode).replaceAllUsesWith(RealDecl);
RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl);
return llvm::DIType(RealDecl);
} }
/// CreateType - get objective-c object type. /// CreateType - get objective-c object type.
@ -1637,6 +1598,26 @@ llvm::DIType CGDebugInfo::getTypeOrNull(QualType Ty) {
return llvm::DIType(); return llvm::DIType();
} }
/// getCompletedTypeOrNull - Get the type from the cache or return null if it
/// doesn't exist.
llvm::DIType CGDebugInfo::getCompletedTypeOrNull(QualType Ty) {
// Unwrap the type as needed for debug information.
Ty = UnwrapTypeForDebugInfo(Ty);
// Check for existing entry.
llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
CompletedTypeCache.find(Ty.getAsOpaquePtr());
if (it != CompletedTypeCache.end()) {
// Verify that the debug info still exists.
if (&*it->second)
return llvm::DIType(cast<llvm::MDNode>(it->second));
}
return llvm::DIType();
}
/// getOrCreateType - Get the type from the cache or create a new /// getOrCreateType - Get the type from the cache or create a new
/// one if necessary. /// one if necessary.
llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) { llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
@ -1646,14 +1627,21 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
// Unwrap the type as needed for debug information. // Unwrap the type as needed for debug information.
Ty = UnwrapTypeForDebugInfo(Ty); Ty = UnwrapTypeForDebugInfo(Ty);
llvm::DIType T = getTypeOrNull(Ty); llvm::DIType T = getCompletedTypeOrNull(Ty);
if (T.Verify()) return T; if (T.Verify()) return T;
// Otherwise create the type. // Otherwise create the type.
llvm::DIType Res = CreateTypeNode(Ty, Unit); llvm::DIType Res = CreateTypeNode(Ty, Unit);
if (T.Verify() && T.isForwardDecl())
T.replaceAllUsesWith(Res);
// And update the type cache. // And update the type cache.
TypeCache[Ty.getAsOpaquePtr()] = Res; TypeCache[Ty.getAsOpaquePtr()] = Res;
if (!Res.isForwardDecl())
CompletedTypeCache[Ty.getAsOpaquePtr()] = Res;
return Res; return Res;
} }
@ -1737,6 +1725,127 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
return llvm::DIType(); return llvm::DIType();
} }
/// getOrCreateLimitedType - Get the type from the cache or create a new
/// limited type if necessary.
llvm::DIType CGDebugInfo::getOrCreateLimitedType(QualType Ty,
llvm::DIFile Unit) {
if (Ty.isNull())
return llvm::DIType();
// Unwrap the type as needed for debug information.
Ty = UnwrapTypeForDebugInfo(Ty);
llvm::DIType T = getTypeOrNull(Ty);
if (T.Verify() && !T.isForwardDecl()) return T;
// Otherwise create the type.
llvm::DIType Res = CreateLimitedTypeNode(Ty, Unit);
if (T.Verify() && T.isForwardDecl())
T.replaceAllUsesWith(Res);
// And update the type cache.
TypeCache[Ty.getAsOpaquePtr()] = Res;
return Res;
}
// TODO: Currently used for context chains when limiting debug info.
llvm::DIType CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
RecordDecl *RD = Ty->getDecl();
// Get overall information about the record type for the debug info.
llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
unsigned Line = getLineNumber(RD->getLocation());
StringRef RDName = RD->getName();
llvm::DIDescriptor RDContext;
if (CGM.getCodeGenOpts().LimitDebugInfo)
RDContext = createContextChain(cast<Decl>(RD->getDeclContext()));
else
RDContext = getContextDescriptor(cast<Decl>(RD->getDeclContext()));
// If this is just a forward declaration, construct an appropriately
// marked node and just return it.
if (!RD->getDefinition()) {
llvm::DIType RTy = createRecordFwdDecl(RD, RDContext);
TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RTy;
return RTy;
}
// Create a temporary type here - different than normal forward declared
// types.
llvm::DIType FwdDecl = DBuilder.createTemporaryType(DefUnit);
llvm::MDNode *MN = FwdDecl;
llvm::TrackingVH<llvm::MDNode> FwdDeclNode = MN;
// Otherwise, insert it into the TypeCache so that recursive uses will find
// it.
TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
llvm::MDNode *RealDecl = NULL;
if (RD->isUnion())
RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line,
Size, Align, 0, llvm::DIArray());
else if (CXXDecl) {
RDName = getClassName(RD);
// A class's primary base or the class itself contains the vtable.
llvm::MDNode *ContainingType = NULL;
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) {
// Seek non virtual primary base root.
while (1) {
const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase);
const CXXRecordDecl *PBT = BRL.getPrimaryBase();
if (PBT && !BRL.isPrimaryBaseVirtual())
PBase = PBT;
else
break;
}
ContainingType =
getOrCreateType(QualType(PBase->getTypeForDecl(), 0), DefUnit);
}
else if (CXXDecl->isDynamicClass())
ContainingType = FwdDecl;
// FIXME: This could be a struct type giving a default visibility different
// than C++ class type, but needs llvm metadata changes first.
RealDecl = DBuilder.createClassType(RDContext, RDName, DefUnit, Line,
Size, Align, 0, 0, llvm::DIType(),
llvm::DIArray(), ContainingType,
llvm::DIArray());
} else
RealDecl = DBuilder.createStructType(RDContext, RDName, DefUnit, Line,
Size, Align, 0, llvm::DIArray());
llvm::DIType(FwdDeclNode).replaceAllUsesWith(RealDecl);
RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl);
return llvm::DIType(RealDecl);
}
/// CreateLimitedTypeNode - Create a new debug type node, but only forward
/// declare composite types that haven't been processed yet.
llvm::DIType CGDebugInfo::CreateLimitedTypeNode(QualType Ty,llvm::DIFile Unit) {
// Work out details of type.
switch (Ty->getTypeClass()) {
#define TYPE(Class, Base)
#define ABSTRACT_TYPE(Class, Base)
#define NON_CANONICAL_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
#include "clang/AST/TypeNodes.def"
llvm_unreachable("Dependent types cannot show up in debug information");
case Type::Record:
return CreateLimitedType(cast<RecordType>(Ty));
default:
return CreateTypeNode(Ty, Unit);
}
}
/// CreateMemberType - Create new member and increase Offset by FType's size. /// CreateMemberType - Create new member and increase Offset by FType's size.
llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType, llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType,
StringRef Name, StringRef Name,

View File

@ -53,6 +53,9 @@ class CGDebugInfo {
/// TypeCache - Cache of previously constructed Types. /// TypeCache - Cache of previously constructed Types.
llvm::DenseMap<void *, llvm::WeakVH> TypeCache; llvm::DenseMap<void *, llvm::WeakVH> TypeCache;
/// CompleteTypeCache - Cache of previously constructed complete RecordTypes.
llvm::DenseMap<void *, llvm::WeakVH> CompletedTypeCache;
bool BlockLiteralGenericSet; bool BlockLiteralGenericSet;
llvm::DIType BlockLiteralGeneric; llvm::DIType BlockLiteralGeneric;
@ -84,6 +87,7 @@ class CGDebugInfo {
llvm::DIType CreateType(const BlockPointerType *Ty, llvm::DIFile F); llvm::DIType CreateType(const BlockPointerType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const FunctionType *Ty, llvm::DIFile F); llvm::DIType CreateType(const FunctionType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const RecordType *Ty); llvm::DIType CreateType(const RecordType *Ty);
llvm::DIType CreateLimitedType(const RecordType *Ty);
llvm::DIType CreateType(const ObjCInterfaceType *Ty, llvm::DIFile F); llvm::DIType CreateType(const ObjCInterfaceType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const ObjCObjectType *Ty, llvm::DIFile F); llvm::DIType CreateType(const ObjCObjectType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const VectorType *Ty, llvm::DIFile F); llvm::DIType CreateType(const VectorType *Ty, llvm::DIFile F);
@ -94,6 +98,7 @@ class CGDebugInfo {
llvm::DIType CreateType(const AtomicType *Ty, llvm::DIFile F); llvm::DIType CreateType(const AtomicType *Ty, llvm::DIFile F);
llvm::DIType CreateEnumType(const EnumDecl *ED); llvm::DIType CreateEnumType(const EnumDecl *ED);
llvm::DIType getTypeOrNull(const QualType); llvm::DIType getTypeOrNull(const QualType);
llvm::DIType getCompletedTypeOrNull(const QualType);
llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method, llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method,
llvm::DIFile F); llvm::DIFile F);
llvm::DIType getOrCreateFunctionType(const Decl *D, QualType FnType, llvm::DIType getOrCreateFunctionType(const Decl *D, QualType FnType,
@ -257,9 +262,17 @@ private:
/// necessary. /// necessary.
llvm::DIType getOrCreateType(QualType Ty, llvm::DIFile F); llvm::DIType getOrCreateType(QualType Ty, llvm::DIFile F);
/// getOrCreateLimitedType - Get the type from the cache or create a new
/// partial type if necessary.
llvm::DIType getOrCreateLimitedType(QualType Ty, llvm::DIFile F);
/// CreateTypeNode - Create type metadata for a source language type. /// CreateTypeNode - Create type metadata for a source language type.
llvm::DIType CreateTypeNode(QualType Ty, llvm::DIFile F); llvm::DIType CreateTypeNode(QualType Ty, llvm::DIFile F);
/// CreateLimitedTypeNode - Create type metadata for a source language
/// type, but only partial types for records.
llvm::DIType CreateLimitedTypeNode(QualType Ty, llvm::DIFile F);
/// CreateMemberType - Create new member and increase Offset by FType's size. /// CreateMemberType - Create new member and increase Offset by FType's size.
llvm::DIType CreateMemberType(llvm::DIFile Unit, QualType FType, llvm::DIType CreateMemberType(llvm::DIFile Unit, QualType FType,
StringRef Name, uint64_t *Offset); StringRef Name, uint64_t *Offset);

View File

@ -1,5 +1,5 @@
// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s // RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s
// XFAIL: *
class Test class Test
{ {
public: public:
@ -19,6 +19,6 @@ protected:
Test t; Test t;
// CHECK: metadata !"data", metadata !7, i32 13, i64 32, i64 32, i32 0, i32 0 // CHECK: metadata !"data", metadata !7, i32 14, i64 32, i64 32, i32 0, i32 0
// CHECK: metadata !"", null, i32 0, i64 64, i64 64, i64 0, i32 0, metadata !5} ; [ DW_TAG_pointer_type ] // CHECK: metadata !"", null, i32 0, i64 64, i64 64, i64 0, i32 0, metadata !5} ; [ DW_TAG_pointer_type ]
// CHECK-NOT: metadata !"data", metadata !7, i32 13, i64 0, i64 0, i32 0, i32 4, // CHECK-NOT: metadata !"data", metadata !7, i32 13, i64 0, i64 0, i32 0, i32 4,