r247049 - Module Debugging: Emit debug type information into clang modules.

David Blaikie via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 8 20:05:00 PDT 2015


On Tue, Sep 8, 2015 at 12:20 PM, Adrian Prantl via cfe-commits <
cfe-commits at lists.llvm.org> wrote:

> Author: adrian
> Date: Tue Sep  8 14:20:27 2015
> New Revision: 247049
>
> URL: http://llvm.org/viewvc/llvm-project?rev=247049&view=rev
> Log:
> Module Debugging: Emit debug type information into clang modules.
>
> When -fmodule-format is set to "obj", emit debug info for all types
> declared in a module or referenced by a declaration into the module's
> object file container.
>
> This patch adds support for C and C++ types.
>
> Added:
>     cfe/trunk/test/Modules/Inputs/DebugCXX.h
>     cfe/trunk/test/Modules/ModuleDebugInfo.cpp
> Modified:
>     cfe/trunk/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
>     cfe/trunk/test/Modules/Inputs/module.map
>
> Modified: cfe/trunk/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ObjectFilePCHContainerOperations.cpp?rev=247049&r1=247048&r2=247049&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/ObjectFilePCHContainerOperations.cpp (original)
> +++ cfe/trunk/lib/CodeGen/ObjectFilePCHContainerOperations.cpp Tue Sep  8
> 14:20:27 2015
> @@ -50,6 +50,34 @@ class PCHContainerGenerator : public AST
>    raw_pwrite_stream *OS;
>    std::shared_ptr<PCHBuffer> Buffer;
>
> +  /// Visit every type and emit debug info for it.
> +  struct DebugTypeVisitor : public RecursiveASTVisitor<DebugTypeVisitor> {
> +    clang::CodeGen::CGDebugInfo &DI;
> +    ASTContext &Ctx;
> +    DebugTypeVisitor(clang::CodeGen::CGDebugInfo &DI, ASTContext &Ctx)
> +        : DI(DI), Ctx(Ctx) {}
> +
> +    /// Determine whether this type can be represented in DWARF.
> +    static bool CanRepresent(const Type *Ty) {
> +      return !Ty->isDependentType() && !Ty->isUndeducedType();
> +    }
> +
> +    bool VisitTypeDecl(TypeDecl *D) {
>

Does this only visit types defined in this module? Or also types otherwise
referenced by this module? (does it only visit definitions, or also
declarations?)


> +      QualType QualTy = Ctx.getTypeDeclType(D);
> +      if (!QualTy.isNull() && CanRepresent(QualTy.getTypePtr()))
> +        DI.getOrCreateStandaloneType(QualTy, D->getLocation());
> +      return true;
> +    }
> +
> +    bool VisitValueDecl(ValueDecl *D) {
>

This seems strange - why would we put this type into the module debug info?
(the type may be defined elsewhere, in another module, etc - just because
there's a variable of that type defined in the module wouldn't imply that
the module should contain a definition of the type, would it? That would
seem to result in a lot of duplicate info)


> +      QualType QualTy = D->getType();
> +      if (!QualTy.isNull() && CanRepresent(QualTy.getTypePtr()))
> +        DI.getOrCreateStandaloneType(QualTy, D->getLocation());
> +      return true;
> +    }
> +
> +  };
> +
>  public:
>    PCHContainerGenerator(DiagnosticsEngine &diags,
>                          const HeaderSearchOptions &HSO,
> @@ -82,6 +110,36 @@ public:
>          *Ctx, HeaderSearchOpts, PreprocessorOpts, CodeGenOpts, *M,
> Diags));
>    }
>
> +  bool HandleTopLevelDecl(DeclGroupRef D) override {
> +    if (Diags.hasErrorOccurred() ||
> +        (CodeGenOpts.getDebugInfo() == CodeGenOptions::NoDebugInfo))
> +      return true;
> +
> +    // Collect debug info for all decls in this group.
> +    for (auto *I : D)
> +      if (!I->isFromASTFile()) {
> +        DebugTypeVisitor DTV(*Builder->getModuleDebugInfo(), *Ctx);
> +        DTV.TraverseDecl(I);
> +      }
> +    return true;
> +  }
> +
> +  void HandleTagDeclDefinition(TagDecl *D) override {
> +    if (Diags.hasErrorOccurred())
>

Is it particularly useful to check for errors here (& in
HandleTagDeclRequiredDefinition below)? That seems like a speed
optimization for the slow case (we're emitting diagnostics anyway, the
speed isn't too important - and we'll still have to be able to discard this
work later in case we haven't seen errors yet, but we do see them later/by
the end of the module?)


> +      return;
> +
> +    Builder->UpdateCompletedType(D);
> +  }
> +
> +  void HandleTagDeclRequiredDefinition(const TagDecl *D) override {
> +    if (Diags.hasErrorOccurred())
> +      return;
> +
> +    if (CodeGen::CGDebugInfo *DI = Builder->getModuleDebugInfo())
> +      if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
> +        DI->completeRequiredType(RD);
> +  }
> +
>    /// Emit a container holding the serialized AST.
>    void HandleTranslationUnit(ASTContext &Ctx) override {
>      assert(M && VMContext && Builder);
>
> Added: cfe/trunk/test/Modules/Inputs/DebugCXX.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/DebugCXX.h?rev=247049&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/Modules/Inputs/DebugCXX.h (added)
> +++ cfe/trunk/test/Modules/Inputs/DebugCXX.h Tue Sep  8 14:20:27 2015
>

A test case involving two modules (where one module depends on the other
and uses its types) would be useful to demonstrate that we aren't
redundantly emitting types into modules that didn't define them, perhaps?


> @@ -0,0 +1,52 @@
> +/* -*- C++ -*- */
> +namespace DebugCXX {
> +  // Records.
> +  struct Struct {
> +    int i;
> +    static int static_member;
> +  };
> +
> +  // Enums.
> +  enum Enum {
> +    Enumerator
> +  };
> +  enum {
> +    e1 = '1'
> +  };
> +  enum {
> +    e2 = '2'
> +  };
> +
> +  // Templates (instatiations).
> +  template<typename T> struct traits {};
> +  template<typename T,
> +           typename Traits = traits<T>
> +          > class Template {
> +    T member;
> +  };
> +  extern template class Template<int>;
> +
> +  extern template struct traits<float>;
> +  typedef class Template<float> FloatInstatiation;
> +
> +  inline void fn() {
> +    Template<long> invisible;
> +  }
> +
> +  // Non-template inside a template.
> +  template <class> struct Outer {
> +    Outer();
> +    struct Inner {
> +      Inner(Outer) {}
> +    };
> +  };
> +  template <class T> Outer<T>::Outer() {
> +    Inner a(*this);
> +  };
> +
> +  // Partial template specialization.
> +  template <typename...> class A;
> +  template <typename T> class A<T> {};
> +  typedef A<void> B;
> +  void foo(B) {}
> +}
>
> Modified: cfe/trunk/test/Modules/Inputs/module.map
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/module.map?rev=247049&r1=247048&r2=247049&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/Modules/Inputs/module.map (original)
> +++ cfe/trunk/test/Modules/Inputs/module.map Tue Sep  8 14:20:27 2015
> @@ -332,6 +332,10 @@ module DebugModule {
>    header "DebugModule.h"
>  }
>
> +module DebugCXX {
> +  header "DebugCXX.h"
> +}
> +
>  module ImportNameInDir {
>    header "ImportNameInDir.h"
>    export *
>
> Added: cfe/trunk/test/Modules/ModuleDebugInfo.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/ModuleDebugInfo.cpp?rev=247049&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/Modules/ModuleDebugInfo.cpp (added)
> +++ cfe/trunk/test/Modules/ModuleDebugInfo.cpp Tue Sep  8 14:20:27 2015
> @@ -0,0 +1,41 @@
> +// Test that (the same) debug info is emitted for an Objective-C++
> +// module and a C++ precompiled header.
> +
> +// REQUIRES: asserts, shell
> +
> +// Modules:
> +// RUN: rm -rf %t
> +// RUN: %clang_cc1 -x objective-c++ -std=c++11 -g -fmodules
> -fmodule-format=obj -fimplicit-module-maps -DMODULES
> -fmodules-cache-path=%t %s -I %S/Inputs -I %t -emit-llvm -o %t.ll -mllvm
> -debug-only=pchcontainer &>%t-mod.ll
> +// RUN: cat %t-mod.ll | FileCheck %s
> +
> +// PCH:
> +// RUN: %clang_cc1 -x c++ -std=c++11 -emit-pch -fmodule-format=obj -I
> %S/Inputs -o %t.pch %S/Inputs/DebugCXX.h -mllvm -debug-only=pchcontainer
> &>%t-pch.ll
> +// RUN: cat %t-pch.ll | FileCheck %s
> +
> +#ifdef MODULES
> + at import DebugCXX;
> +#endif
> +
>

If practical, it'd be nice to have these checks near the things tehy're
checking for - it'd make the code easier to read/understand. (haven't
looked at related tests in the same directory to see what the convention's
like)


> +// CHECK: distinct !DICompileUnit(language: DW_LANG_{{.*}}C_plus_plus,
> +// CHECK-SAME:                    isOptimized: false,
> +// CHECK-SAME:                    splitDebugFilename:
> +// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, name: "Enum"
> +// CHECK-SAME:             identifier: "_ZTSN8DebugCXX4EnumE")
> +// CHECK: !DINamespace(name: "DebugCXX"
> +// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Struct"
> +// CHECK-SAME:             identifier: "_ZTSN8DebugCXX6StructE")
> +// CHECK: !DICompositeType(tag: DW_TAG_class_type,
> +// CHECK-SAME:             name: "Template<int, DebugCXX::traits<int> >"
> +// CHECK-SAME:             identifier:
> "_ZTSN8DebugCXX8TemplateIiNS_6traitsIiEEEE")
> +// CHECK: !DICompositeType(tag: DW_TAG_class_type,
> +// CHECK-SAME:             name: "Template<float, DebugCXX::traits<float>
> >"
> +// CHECK-SAME:             identifier:
> "_ZTSN8DebugCXX8TemplateIfNS_6traitsIfEEEE")
> +// CHECK: !DICompositeType(tag: DW_TAG_class_type,
> +// CHECK-SAME:             name: "Template<long, DebugCXX::traits<long> >"
> +// CHECK-SAME:             identifier:
> "_ZTSN8DebugCXX8TemplateIlNS_6traitsIlEEEE")
> +// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "A<void>"
> +// CHECK-SAME:             identifier: "_ZTSN8DebugCXX1AIJvEEE")
> +// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "FloatInstatiation"
> +// no mangled name here yet.
>

Is this a 'fixme'? (might be good to phrase it that way) - any idea why
they're missing?


> +// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "B",
> +// no mangled name here yet.
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20150908/713430a2/attachment-0001.html>


More information about the cfe-commits mailing list