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)

Pete Cooper peter_cooper at apple.com
Tue Mar 4 09:50:53 PST 2014


On Mar 3, 2014, at 7:15 PM, David Blaikie <dblaikie at gmail.com> wrote:

> 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.
I had no idea we even had that option, nor that it was on by default!  Thanks for the quick fix.

Pete
> 
>> 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