From ebbd7e07aa0f22722da6ed8dd3a55beed9699171 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Mon, 11 Mar 2013 18:33:46 +0000 Subject: [PATCH] Improve the caching of debuginfo Objective C interface types. Generate forward declarations that are RAUW'd by finalize(). We thus avoid outputting the same type several times in multiple stages of completion. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@176820 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGDebugInfo.cpp | 86 +++++++++++++------ lib/CodeGen/CGDebugInfo.h | 4 + test/CodeGenObjC/debug-info-ivars-extension.m | 5 ++ 3 files changed, 68 insertions(+), 27 deletions(-) diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 8d6352c404..a139597c26 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -1314,7 +1314,7 @@ llvm::DIType CGDebugInfo::getOrCreateInterfaceType(QualType D, SourceLocation Loc) { assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); llvm::DIType T = getOrCreateType(D, getOrCreateFile(Loc)); - DBuilder.retainType(T); + RetainedTypes.push_back(D.getAsOpaquePtr()); return T; } @@ -1778,6 +1778,13 @@ llvm::DIType CGDebugInfo::getTypeOrNull(QualType Ty) { Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext()); // Check for existing entry. + if (Ty->getTypeClass() == Type::ObjCInterface) { + llvm::Value *V = getCachedInterfaceTypeOrNull(Ty); + if (V) + return llvm::DIType(cast(V)); + else return llvm::DIType(); + } + llvm::DenseMap::iterator it = TypeCache.find(Ty.getAsOpaquePtr()); if (it != TypeCache.end()) { @@ -1803,16 +1810,7 @@ llvm::DIType CGDebugInfo::getCompletedTypeOrNull(QualType Ty) { if (it != CompletedTypeCache.end()) V = it->second; else { - // Is there a cached interface that hasn't changed? - llvm::DenseMap > - ::iterator it1 = ObjCInterfaceCache.find(Ty.getAsOpaquePtr()); - - if (it1 != ObjCInterfaceCache.end()) - if (ObjCInterfaceDecl* Decl = getObjCInterfaceDecl(Ty)) - if (Checksum(Decl) == it1->second.second) { - // Return cached type. - V = it1->second.first; - } + V = getCachedInterfaceTypeOrNull(Ty); } // Verify that any cached debug info still exists. @@ -1822,6 +1820,21 @@ llvm::DIType CGDebugInfo::getCompletedTypeOrNull(QualType Ty) { return llvm::DIType(); } +/// getCachedInterfaceTypeOrNull - Get the type from the interface +/// cache, unless it needs to regenerated. Otherwise return null. +llvm::Value *CGDebugInfo::getCachedInterfaceTypeOrNull(QualType Ty) { + // Is there a cached interface that hasn't changed? + llvm::DenseMap > + ::iterator it1 = ObjCInterfaceCache.find(Ty.getAsOpaquePtr()); + + if (it1 != ObjCInterfaceCache.end()) + if (ObjCInterfaceDecl* Decl = getObjCInterfaceDecl(Ty)) + if (Checksum(Decl) == it1->second.second) + // Return cached forward declaration. + return it1->second.first; + + return 0; +} /// getOrCreateType - Get the type from the cache or create a new /// one if necessary. @@ -1839,27 +1852,39 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) { // Otherwise create the type. llvm::DIType Res = CreateTypeNode(Ty, Unit); + void* TyPtr = Ty.getAsOpaquePtr(); + + // And update the type cache. + TypeCache[TyPtr] = Res; llvm::DIType TC = getTypeOrNull(Ty); if (TC.Verify() && TC.isForwardDecl()) - ReplaceMap.push_back(std::make_pair(Ty.getAsOpaquePtr(), - static_cast(TC))); - - // Do not cache the type if it may be incomplete. - if (ObjCInterfaceDecl* Decl = getObjCInterfaceDecl(Ty)) { - // clang::ParseAST handles each TopLevelDecl immediately after it was parsed. - // A subsequent implementation may add more ivars to an interface, which is - // why we cache it together with a checksum to see if it changed. - ObjCInterfaceCache[Ty.getAsOpaquePtr()] = - std::make_pair(Res, Checksum(Decl)); - return Res; - } + ReplaceMap.push_back(std::make_pair(TyPtr, static_cast(TC))); + else if (ObjCInterfaceDecl* Decl = getObjCInterfaceDecl(Ty)) { + // Interface types may have elements added to them by a + // subsequent implementation or extension, so we keep them in + // the ObjCInterfaceCache together with a checksum. Instead of + // the (possibly) incomplete interace type, we return a forward + // declaration that gets RAUW'd in CGDebugInfo::finalize(). + llvm::DenseMap > + ::iterator it = ObjCInterfaceCache.find(TyPtr); + if (it != ObjCInterfaceCache.end()) + TC = llvm::DIType(cast(it->second.first)); + else + TC = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, + Decl->getName(), TheCU, Unit, + getLineNumber(Decl->getLocation()), + TheCU.getLanguage()); + // Store the forward declaration in the cache. + ObjCInterfaceCache[TyPtr] = std::make_pair(TC, Checksum(Decl)); - // And update the type cache. - TypeCache[Ty.getAsOpaquePtr()] = Res; + // Register the type for replacement in finalize(). + ReplaceMap.push_back(std::make_pair(TyPtr, static_cast(TC))); + return TC; + } if (!Res.isForwardDecl()) - CompletedTypeCache[Ty.getAsOpaquePtr()] = Res; + CompletedTypeCache[TyPtr] = Res; return Res; } @@ -2929,10 +2954,17 @@ void CGDebugInfo::finalize() { if (llvm::Value *V = it->second) RepTy = llvm::DIType(cast(V)); } - + if (Ty.Verify() && Ty.isForwardDecl() && RepTy.Verify()) { Ty.replaceAllUsesWith(RepTy); } } + + // We keep our own list of retained types, because we need to look + // up the final type in the type cache. + for (std::vector::const_iterator RI = RetainedTypes.begin(), + RE = RetainedTypes.end(); RI != RE; ++RI) + DBuilder.retainType(llvm::DIType(cast(TypeCache[*RI]))); + DBuilder.finalize(); } diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 9650f2e00f..2e896cfe22 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -66,6 +66,9 @@ class CGDebugInfo { llvm::DenseMap > ObjCInterfaceCache; + /// RetainedTypes - list of interfaces we want to keep even if orphaned. + std::vector RetainedTypes; + /// CompleteTypeCache - Cache of previously constructed complete RecordTypes. llvm::DenseMap CompletedTypeCache; @@ -131,6 +134,7 @@ class CGDebugInfo { const Type *Ty, QualType PointeeTy, llvm::DIFile F); + llvm::Value *getCachedInterfaceTypeOrNull(const QualType Ty); llvm::DIType getOrCreateStructPtrType(StringRef Name, llvm::DIType &Cache); llvm::DISubprogram CreateCXXMemberFunction(const CXXMethodDecl *Method, diff --git a/test/CodeGenObjC/debug-info-ivars-extension.m b/test/CodeGenObjC/debug-info-ivars-extension.m index aca1917bb5..733d146875 100644 --- a/test/CodeGenObjC/debug-info-ivars-extension.m +++ b/test/CodeGenObjC/debug-info-ivars-extension.m @@ -24,5 +24,10 @@ void gorf (I* pg) { int _b = pg->b; } +// CHECK: metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata !"I", {{.*}}} ; [ DW_TAG_structure_type ] +// Check for "a". // CHECK: metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata !"a", metadata !{{[0-9]*}}, i32 7, i64 32, i64 32, i64 0, i32 0, metadata !{{[0-9]*}}, null} ; [ DW_TAG_member ] [a] [line 7, size 32, align 32, offset 0] [from int] +// Make sure we don't output the same type twice. +// CHECK-NOT: metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata !"I", {{.*}}} ; [ DW_TAG_structure_type ] +// Check for "b". // CHECK: metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata !"b", metadata !{{[0-9]*}}, i32 18, i64 32, i64 32, i64 0, i32 0, metadata !{{[0-9]*}}, null} ; [ DW_TAG_member ] [b] [line 18, size 32, align 32, offset 0] [from int] -- 2.40.0