summaryrefslogtreecommitdiff
path: root/lib/CodeGen/CGDebugInfo.cpp
diff options
context:
space:
mode:
authorDavid Blaikie <dblaikie@gmail.com>2014-03-03 23:48:23 +0000
committerDavid Blaikie <dblaikie@gmail.com>2014-03-03 23:48:23 +0000
commitb6b24026464c7c5053e1903a27f4dd1f95faf5c8 (patch)
treea568ccf699ab9d290143c1a06b8376f633ed2b2e /lib/CodeGen/CGDebugInfo.cpp
parente135cdfaf92fabceffbedc42d4fe829898aa3f0e (diff)
downloadclang-b6b24026464c7c5053e1903a27f4dd1f95faf5c8.tar.gz
clang-b6b24026464c7c5053e1903a27f4dd1f95faf5c8.tar.bz2
clang-b6b24026464c7c5053e1903a27f4dd1f95faf5c8.tar.xz
DebugInfo: Emit only the declaration of a class template that has an explicit instantiation declaration (& always emit such a type when there's an explicit instantiation definition)
We should only have this optimization fire when the explicit instantiation definition would cause at least one member function to be emitted, thus ensuring that even a compiler not performing this optimization would still emit the full type information elsewhere. But we should also pessimize output still by always emitting the definition when the explicit instantiation definition appears so that at some point in the future we can depend on that information even when no code had to be emitted in that TU. (this shouldn't happen very often, since people mostly use explicit spec decl/defs to reduce code size - but perhaps one day they could use it to explicitly reduce debug info size too) This was worth about 2% for Clang and LLVM - so not a huge win, but a win. It looks really great for simple STL programs (include <string> and just declare a string - 14k -> 1.4k of .dwo) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@202769 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGDebugInfo.cpp')
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp69
1 files changed, 51 insertions, 18 deletions
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 633078fb3b..6c24e8f865 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -1458,28 +1458,53 @@ void CGDebugInfo::completeClassData(const RecordDecl *RD) {
TypeCache[TyPtr] = Res;
}
+static bool hasExplicitMemberDefinition(CXXRecordDecl::method_iterator I,
+ CXXRecordDecl::method_iterator End) {
+ for (; I != End; ++I)
+ if (FunctionDecl *Tmpl = I->getInstantiatedFromMemberFunction())
+ if (!Tmpl->isImplicit() && Tmpl->hasBody())
+ return true;
+ return false;
+}
+
+static bool shouldOmitDefinition(CodeGenOptions::DebugInfoKind DebugKind,
+ const RecordDecl *RD,
+ const LangOptions &LangOpts) {
+ if (DebugKind > CodeGenOptions::LimitedDebugInfo)
+ return false;
+
+ if (!LangOpts.CPlusPlus)
+ return false;
+
+ if (!RD->isCompleteDefinitionRequired())
+ return true;
+
+ const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
+
+ if (!CXXDecl)
+ return false;
+
+ if (CXXDecl->hasDefinition() && CXXDecl->isDynamicClass())
+ return true;
+
+ TemplateSpecializationKind Spec = TSK_Undeclared;
+ if (const ClassTemplateSpecializationDecl *SD =
+ dyn_cast<ClassTemplateSpecializationDecl>(RD))
+ Spec = SD->getSpecializationKind();
+
+ if (Spec == TSK_ExplicitInstantiationDeclaration &&
+ hasExplicitMemberDefinition(CXXDecl->method_begin(),
+ CXXDecl->method_end()))
+ return true;
+
+ return false;
+}
+
/// CreateType - get structure or union type.
llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
RecordDecl *RD = Ty->getDecl();
- const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
- // Always emit declarations for types that aren't required to be complete when
- // in limit-debug-info mode. If the type is later found to be required to be
- // complete this declaration will be upgraded to a definition by
- // `completeRequiredType`.
- // If the type is dynamic, only emit the definition in TUs that require class
- // data. This is handled by `completeClassData`.
llvm::DICompositeType T(getTypeOrNull(QualType(Ty, 0)));
- // If we've already emitted the type, just use that, even if it's only a
- // declaration. The completeType, completeRequiredType, and completeClassData
- // callbacks will handle promoting the declaration to a definition.
- if (T ||
- // Under -fno-standalone-debug:
- (DebugKind <= CodeGenOptions::LimitedDebugInfo &&
- // Emit only a forward declaration unless the type is required.
- ((!RD->isCompleteDefinitionRequired() && CGM.getLangOpts().CPlusPlus) ||
- // If the class is dynamic, only emit a declaration. A definition will
- // be emitted whenever the vtable is emitted.
- (CXXDecl && CXXDecl->hasDefinition() && CXXDecl->isDynamicClass())))) {
+ if (T || shouldOmitDefinition(DebugKind, RD, CGM.getLangOpts())) {
if (!T)
T = getOrCreateRecordFwdDecl(
Ty, getContextDescriptor(cast<Decl>(RD->getDeclContext())));
@@ -2014,6 +2039,14 @@ llvm::DIType CGDebugInfo::getCompletedTypeOrNull(QualType Ty) {
return llvm::DIType(cast_or_null<llvm::MDNode>(V));
}
+void CGDebugInfo::completeTemplateDefinition(
+ const ClassTemplateSpecializationDecl &SD) {
+ completeClassData(&SD);
+ // In case this type has no member function definitions being emitted, ensure
+ // it is retained
+ RetainedTypes.push_back(CGM.getContext().getRecordType(&SD).getAsOpaquePtr());
+}
+
/// getCachedInterfaceTypeOrNull - Get the type from the interface
/// cache, unless it needs to regenerated. Otherwise return null.
llvm::Value *CGDebugInfo::getCachedInterfaceTypeOrNull(QualType Ty) {