FlameTop created this revision.
FlameTop added a reviewer: rsmith.
FlameTop added a subscriber: cfe-commits.

The provided test shows a case where enabling coverage instrumentation causes a 
link error during building. Normally the all the base class items (vtable, 
ctors and dtors) would be removed in an optimized build. But when building with 
coverage instrumentation the ctors and dtors are always issued and access the 
vtable. However, the vtable remains with external linkage. As nobody ever 
instantiates the base class the vtable remains undefined and causes a link 
error.

This patch changes the behavior when deciding the vtable linkage when 
generating coverage instrumentation. vtables are always generated as local 
linkonce objects.

This is slightly wasteful of link time and target storage but the profile 
instrumentation is performed too early (as far as I can see) to not instrument 
ctors/dtors that will later be discarded.


https://reviews.llvm.org/D27410

Files:
  llvm/tools/clang/lib/CodeGen/CGVTables.cpp
  llvm/tools/clang/test/CodeGenCXX/vtable-coverage-gen.cpp


Index: llvm/tools/clang/test/CodeGenCXX/vtable-coverage-gen.cpp
===================================================================
--- /dev/null
+++ llvm/tools/clang/test/CodeGenCXX/vtable-coverage-gen.cpp
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -O2 -fprofile-instrument=clang -fcoverage-mapping %s 
-emit-llvm -o %t
+// RUN: FileCheck %s < %t 
+// CHECK: @_ZTV8Category = linkonce_odr unnamed_addr constant {{.*}}, comdat,
+
+class Category
+{
+  public:
+ Category() {}
+ virtual ~Category() {}
+
+ static const Category *Get(int source);
+
+
+  protected:
+ const char *const ITEM_KEY_CONSOLE_ID = "consoleId";
+
+};
+
+
+
+class CategoryAboutMe : public Category
+{
+  public:
+ CategoryAboutMe() {}
+ virtual ~CategoryAboutMe() {}
+
+  protected:
+};
+
+
+//static
+const Category *
+Category::Get(int source)
+{
+ static CategoryAboutMe s_categoryAboutMe;
+
+ switch (source) {
+ case 0:
+  return &s_categoryAboutMe;
+ default:
+  return __null;
+ }
+  return 0;
+}
+
+
+int main(int argc, char const *argv[])
+{
+  /* code */
+  return 0;
+}
\ No newline at end of file
Index: llvm/tools/clang/lib/CodeGen/CGVTables.cpp
===================================================================
--- llvm/tools/clang/lib/CodeGen/CGVTables.cpp
+++ llvm/tools/clang/lib/CodeGen/CGVTables.cpp
@@ -715,9 +715,17 @@
     const FunctionDecl *def = nullptr;
     if (keyFunction->hasBody(def))
       keyFunction = cast<CXXMethodDecl>(def);
-
     switch (keyFunction->getTemplateSpecializationKind()) {
       case TSK_Undeclared:
+        // if we are generating profile instrumentation ensure
+        // vtables are always issued locally as the constructors
+        // and destructors are always issued.
+        if (CodeGenOpts.hasProfileClangInstr() ||
+            CodeGenOpts.hasProfileIRInstr())
+          return !Context.getLangOpts().AppleKext ?
+                   llvm::GlobalVariable::LinkOnceODRLinkage :
+                   llvm::Function::InternalLinkage;
+        LLVM_FALLTHROUGH;
       case TSK_ExplicitSpecialization:
         assert((def || CodeGenOpts.OptimizationLevel > 0) &&
                "Shouldn't query vtable linkage without key function or "
@@ -821,6 +829,12 @@
 bool CodeGenVTables::isVTableExternal(const CXXRecordDecl *RD) {
   assert(RD->isDynamicClass() && "Non-dynamic classes have no VTable.");
 
+  // if we are generating profile instrumentation, issue the vtables locally as
+  // the constructors and destructors will always be issued.
+  if (CGM.getCodeGenOpts().hasProfileClangInstr() ||
+      CGM.getCodeGenOpts().hasProfileIRInstr())
+    return false;
+
   // We always synthesize vtables if they are needed in the MS ABI. MSVC 
doesn't
   // emit them even if there is an explicit template instantiation.
   if (CGM.getTarget().getCXXABI().isMicrosoft())


Index: llvm/tools/clang/test/CodeGenCXX/vtable-coverage-gen.cpp
===================================================================
--- /dev/null
+++ llvm/tools/clang/test/CodeGenCXX/vtable-coverage-gen.cpp
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -O2 -fprofile-instrument=clang -fcoverage-mapping %s -emit-llvm -o %t
+// RUN: FileCheck %s < %t 
+// CHECK: @_ZTV8Category = linkonce_odr unnamed_addr constant {{.*}}, comdat,
+
+class Category
+{
+  public:
+ Category() {}
+ virtual ~Category() {}
+
+ static const Category *Get(int source);
+
+
+  protected:
+ const char *const ITEM_KEY_CONSOLE_ID = "consoleId";
+
+};
+
+
+
+class CategoryAboutMe : public Category
+{
+  public:
+ CategoryAboutMe() {}
+ virtual ~CategoryAboutMe() {}
+
+  protected:
+};
+
+
+//static
+const Category *
+Category::Get(int source)
+{
+ static CategoryAboutMe s_categoryAboutMe;
+
+ switch (source) {
+ case 0:
+  return &s_categoryAboutMe;
+ default:
+  return __null;
+ }
+  return 0;
+}
+
+
+int main(int argc, char const *argv[])
+{
+  /* code */
+  return 0;
+}
\ No newline at end of file
Index: llvm/tools/clang/lib/CodeGen/CGVTables.cpp
===================================================================
--- llvm/tools/clang/lib/CodeGen/CGVTables.cpp
+++ llvm/tools/clang/lib/CodeGen/CGVTables.cpp
@@ -715,9 +715,17 @@
     const FunctionDecl *def = nullptr;
     if (keyFunction->hasBody(def))
       keyFunction = cast<CXXMethodDecl>(def);
-
     switch (keyFunction->getTemplateSpecializationKind()) {
       case TSK_Undeclared:
+        // if we are generating profile instrumentation ensure
+        // vtables are always issued locally as the constructors
+        // and destructors are always issued.
+        if (CodeGenOpts.hasProfileClangInstr() ||
+            CodeGenOpts.hasProfileIRInstr())
+          return !Context.getLangOpts().AppleKext ?
+                   llvm::GlobalVariable::LinkOnceODRLinkage :
+                   llvm::Function::InternalLinkage;
+        LLVM_FALLTHROUGH;
       case TSK_ExplicitSpecialization:
         assert((def || CodeGenOpts.OptimizationLevel > 0) &&
                "Shouldn't query vtable linkage without key function or "
@@ -821,6 +829,12 @@
 bool CodeGenVTables::isVTableExternal(const CXXRecordDecl *RD) {
   assert(RD->isDynamicClass() && "Non-dynamic classes have no VTable.");
 
+  // if we are generating profile instrumentation, issue the vtables locally as
+  // the constructors and destructors will always be issued.
+  if (CGM.getCodeGenOpts().hasProfileClangInstr() ||
+      CGM.getCodeGenOpts().hasProfileIRInstr())
+    return false;
+
   // We always synthesize vtables if they are needed in the MS ABI. MSVC doesn't
   // emit them even if there is an explicit template instantiation.
   if (CGM.getTarget().getCXXABI().isMicrosoft())
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to