r202769 - 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)

David Blaikie dblaikie at gmail.com
Mon Mar 3 19:15:56 PST 2014


On Mon, Mar 3, 2014 at 7:05 PM, Pete Cooper <peter_cooper at apple.com> wrote:
> Hey David
>
> We had a failure with this test on our buildbots.  Seems Mac OS doesn't
> generate the same debug info for 'c':

Ah, sorry about that - didn't realize darwin's default of
-fstandalone-debug was built into the frontend (well, I forgot that
was still the darwin default at all). Changed the test to explicitly
specify -fno-standalone-debug.

> llvm/tools/clang/test/CodeGenCXX/debug-info-template-explicit-specialization.cpp:22:11:
> error: expected string not found in input
> // CHECK: ; [ DW_TAG_structure_type ] [c<int>] {{.*}} [decl]
>           ^
> <stdin>:27:252: note: scanning from here
> !4 = metadata !{i32 786451, metadata !5, null, metadata !"b<int>", i32 12,
> i64 8, i64 8, i32 0, i32 0, null, metadata !2, i32 0, null, metadata !6,
> metadata !"_ZTS1bIiE"} ; [ DW_TAG_structure_type ] [b<int>] [line 12, size
> 8, align 8, offset 0] [def] [from ]
>
> ^
> <stdin>:32:170: note: possible intended match here
> !9 = metadata !{i32 786451, metadata !5, null, metadata !"c<int>", i32 20,
> i64 8, i64 8, i32 0, i32 0, null, metadata !10, i32 0, null, metadata !6,
> metadata !"_ZTS1cIiE"} ; [ DW_TAG_structure_type ] [c<int>] [line 20, size
> 8, align 8, offset 0] [def] [from ]
>
> I committed a fix in 202777.  Please take a look and see if you think its
> ok.
>
> Thanks,
> Pete
> On Mar 3, 2014, at 3:48 PM, David Blaikie <dblaikie at gmail.com> wrote:
>
> Author: dblaikie
> Date: Mon Mar  3 17:48:23 2014
> New Revision: 202769
>
> URL: http://llvm.org/viewvc/llvm-project?rev=202769&view=rev
> Log:
> 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)
>
> Added:
>    cfe/trunk/test/CodeGenCXX/debug-info-template-explicit-specialization.cpp
> Modified:
>    cfe/trunk/lib/CodeGen/CGDebugInfo.cpp
>    cfe/trunk/lib/CodeGen/CGDebugInfo.h
>    cfe/trunk/lib/CodeGen/CodeGenModule.cpp
>
> Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.cpp?rev=202769&r1=202768&r2=202769&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGDebugInfo.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGDebugInfo.cpp Mon Mar  3 17:48:23 2014
> @@ -1458,28 +1458,53 @@ void CGDebugInfo::completeClassData(cons
>   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::getCompletedTy
>   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) {
>
> Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.h?rev=202769&r1=202768&r2=202769&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGDebugInfo.h (original)
> +++ cfe/trunk/lib/CodeGen/CGDebugInfo.h Mon Mar  3 17:48:23 2014
> @@ -288,6 +288,8 @@ public:
>   void completeRequiredType(const RecordDecl *RD);
>   void completeClassData(const RecordDecl *RD);
>
> +  void completeTemplateDefinition(const ClassTemplateSpecializationDecl
> &SD);
> +
> private:
>   /// EmitDeclare - Emit call to llvm.dbg.declare for a variable
> declaration.
>   void EmitDeclare(const VarDecl *decl, unsigned Tag, llvm::Value *AI,
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=202769&r1=202768&r2=202769&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Mon Mar  3 17:48:23 2014
> @@ -3000,7 +3000,15 @@ void CodeGenModule::EmitTopLevelDecl(Dec
>
>     ImportedModules.insert(Import->getImportedModule());
>     break;
> - }
> +  }
> +
> +  case Decl::ClassTemplateSpecialization: {
> +    const ClassTemplateSpecializationDecl *Spec =
> +        cast<ClassTemplateSpecializationDecl>(D);
> +    if (DebugInfo &&
> +        Spec->getSpecializationKind() ==
> TSK_ExplicitInstantiationDefinition)
> +      DebugInfo->completeTemplateDefinition(*Spec);
> +  }
>
>   default:
>     // Make sure we handled everything we should, every other kind is a
>
> Added:
> cfe/trunk/test/CodeGenCXX/debug-info-template-explicit-specialization.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/debug-info-template-explicit-specialization.cpp?rev=202769&view=auto
> ==============================================================================
> ---
> cfe/trunk/test/CodeGenCXX/debug-info-template-explicit-specialization.cpp
> (added)
> +++
> cfe/trunk/test/CodeGenCXX/debug-info-template-explicit-specialization.cpp
> Mon Mar  3 17:48:23 2014
> @@ -0,0 +1,72 @@
> +// RUN: %clang_cc1 -S -emit-llvm -g %s -o - | FileCheck %s
> +
> +template <typename T>
> +struct a {
> +};
> +extern template class a<int>;
> +// CHECK-NOT: ; [ DW_TAG_structure_type ] [a<int>]
> +
> +template <typename T>
> +struct b {
> +};
> +extern template class b<int>;
> +b<int> bi;
> +// CHECK: ; [ DW_TAG_structure_type ] [b<int>] {{.*}} [def]
> +
> +template <typename T>
> +struct c {
> +  void f() {}
> +};
> +extern template class c<int>;
> +c<int> ci;
> +// CHECK: ; [ DW_TAG_structure_type ] [c<int>] {{.*}} [decl]
> +
> +template <typename T>
> +struct d {
> +  void f();
> +};
> +extern template class d<int>;
> +d<int> di;
> +// CHECK: ; [ DW_TAG_structure_type ] [d<int>] {{.*}} [def]
> +
> +template <typename T>
> +struct e {
> +  void f();
> +};
> +template <typename T>
> +void e<T>::f() {
> +}
> +extern template class e<int>;
> +e<int> ei;
> +// CHECK: ; [ DW_TAG_structure_type ] [e<int>] {{.*}} [decl]
> +
> +template <typename T>
> +struct f {
> +  void g();
> +};
> +extern template class f<int>;
> +template <typename T>
> +void f<T>::g() {
> +}
> +f<int> fi;
> +// Is this right? We don't seem to emit a def for 'f<int>::g' (even if it
> is
> +// called in this translation unit) so I guess if we're relying on its
> +// definition to be wherever the explicit instantiation definition is, we
> can do
> +// the same for the debug info.
> +// CHECK: ; [ DW_TAG_structure_type ] [f<int>] {{.*}} [decl]
> +
> +template <typename T>
> +struct g {
> +  void f();
> +};
> +template <>
> +void g<int>::f();
> +extern template class g<int>;
> +g<int> gi;
> +// CHECK: ; [ DW_TAG_structure_type ] [g<int>] {{.*}} [def]
> +
> +template <typename T>
> +struct h {
> +};
> +template class h<int>;
> +// CHECK: ; [ DW_TAG_structure_type ] [h<int>] {{.*}} [def]
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
>



More information about the cfe-commits mailing list