[cfe-commits] r124565 - in /cfe/trunk: lib/CodeGen/CGRTTI.cpp lib/CodeGen/CGVTables.cpp lib/CodeGen/CodeGenModule.cpp lib/Sema/SemaDeclCXX.cpp test/CodeGenCXX/vtable-available-externally.cpp

Anders Carlsson andersca at mac.com
Sun Jan 30 12:45:55 PST 2011


Author: andersca
Date: Sun Jan 30 14:45:54 2011
New Revision: 124565

URL: http://llvm.org/viewvc/llvm-project?rev=124565&view=rev
Log:
When building with optimizations, emit vtables where the key is not in the 
current translation unit as available_externally. 

This helps devirtualize the second example in PR3100, comment 18:

struct S { S() {}; virtual void xyzzy(); };
inline void foo(S *s) { s->xyzzy(); }
void bar() { S s; foo(&s); }

This involved four major changes:

1. In DefineUsedVTables, always mark virtual member functions as referenced for
   non-template classes and class template specializations.
2. In CodeGenVTables::ShouldEmitVTableInThisTU return true if optimizations are
   enabled, even if the key function is not implemented in this translation 
   unit. We don't ever do this for code compiled with -fapple-kext, because we
   don't ever want to devirtualize virtual member function calls in that case.
3. Give the correct linkage for vtables where the key function is not defined.
4. Update the linkage for RTTI structures when necessary.

Added:
    cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp
Modified:
    cfe/trunk/lib/CodeGen/CGRTTI.cpp
    cfe/trunk/lib/CodeGen/CGVTables.cpp
    cfe/trunk/lib/CodeGen/CodeGenModule.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp

Modified: cfe/trunk/lib/CodeGen/CGRTTI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGRTTI.cpp?rev=124565&r1=124564&r2=124565&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGRTTI.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGRTTI.cpp Sun Jan 30 14:45:54 2011
@@ -484,6 +484,58 @@
   Fields.push_back(VTable);
 }
 
+// maybeUpdateRTTILinkage - Will update the linkage of the RTTI data structures
+// from available_externally to the correct linkage if necessary. An example of
+// this is:
+//
+//   struct A {
+//     virtual void f();
+//   };
+//
+//   const std::type_info &g() {
+//     return typeid(A);
+//   }
+//
+//   void A::f() { }
+//
+// When we're generating the typeid(A) expression, we do not yet know that
+// A's key function is defined in this translation unit, so we will give the
+// typeinfo and typename structures available_externally linkage. When A::f
+// forces the vtable to be generated, we need to change the linkage of the
+// typeinfo and typename structs, otherwise we'll end up with undefined
+// externals when linking.
+static void 
+maybeUpdateRTTILinkage(CodeGenModule &CGM, llvm::GlobalVariable *GV,
+                       QualType Ty) {
+  // We're only interested in globals with available_externally linkage.
+  if (!GV->hasAvailableExternallyLinkage())
+    return;
+
+  // Get the real linkage for the type.
+  llvm::GlobalVariable::LinkageTypes Linkage = getTypeInfoLinkage(CGM, Ty);
+
+  // If variable is supposed to have available_externally linkage, we don't
+  // need to do anything.
+  if (Linkage == llvm::GlobalVariable::AvailableExternallyLinkage)
+    return;
+
+  // Update the typeinfo linkage.
+  GV->setLinkage(Linkage);
+
+  // Get the typename global.
+  llvm::SmallString<256> OutName;
+  CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, OutName);
+  llvm::StringRef Name = OutName.str();
+
+  llvm::GlobalVariable *TypeNameGV = CGM.getModule().getNamedGlobal(Name);
+
+  assert(TypeNameGV->hasAvailableExternallyLinkage() &&
+         "Type name has different linkage from type info!");
+
+  // And update its linkage.
+  TypeNameGV->setLinkage(Linkage);
+}
+
 llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
   // We want to operate on the canonical type.
   Ty = CGM.getContext().getCanonicalType(Ty);
@@ -494,8 +546,11 @@
   llvm::StringRef Name = OutName.str();
 
   llvm::GlobalVariable *OldGV = CGM.getModule().getNamedGlobal(Name);
-  if (OldGV && !OldGV->isDeclaration())
+  if (OldGV && !OldGV->isDeclaration()) {
+    maybeUpdateRTTILinkage(CGM, OldGV, Ty);
+
     return llvm::ConstantExpr::getBitCast(OldGV, Int8PtrTy);
+  }
 
   // Check if there is already an external RTTI descriptor for this type.
   bool IsStdLib = IsStandardLibraryRTTIDescriptor(Ty);

Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=124565&r1=124564&r2=124565&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGVTables.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGVTables.cpp Sun Jan 30 14:45:54 2011
@@ -2374,6 +2374,12 @@
       TSK == TSK_ExplicitInstantiationDefinition)
     return true;
 
+  // If we're building with optimization, we always emit VTables since that
+  // allows for virtual function calls to be devirtualized.
+  // (We don't want to do this in -fapple-kext mode however).
+  if (CGM.getCodeGenOpts().OptimizationLevel && !CGM.getLangOptions().AppleKext)
+    return true;
+
   return KeyFunction->hasBody();
 }
 

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=124565&r1=124564&r2=124565&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Sun Jan 30 14:45:54 2011
@@ -1082,6 +1082,12 @@
     switch (KeyFunction->getTemplateSpecializationKind()) {
       case TSK_Undeclared:
       case TSK_ExplicitSpecialization:
+        // When compiling with optimizations turned on, we emit all vtables,
+        // even if the key function is not defined in the current translation
+        // unit. If this is the case, use available_externally linkage.
+        if (!Def && CodeGenOpts.OptimizationLevel)
+          return llvm::GlobalVariable::AvailableExternallyLinkage;
+
         if (KeyFunction->isInlined())
           return llvm::GlobalVariable::LinkOnceODRLinkage;
         

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=124565&r1=124564&r2=124565&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sun Jan 30 14:45:54 2011
@@ -7110,6 +7110,13 @@
       switch (KeyFunction->getTemplateSpecializationKind()) {
       case TSK_Undeclared:
       case TSK_ExplicitSpecialization:
+        // The key function is in another translation unit. Mark all of the
+        // virtual members of this class as referenced so that we can build a
+        // vtable anyway (in order to do devirtualization when optimizations
+        // are turned on for example.
+        MarkVirtualMembersReferenced(Loc, Class);
+        continue;
+
       case TSK_ExplicitInstantiationDeclaration:
         // The key function is in another translation unit.
         continue;

Added: cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp?rev=124565&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp Sun Jan 30 14:45:54 2011
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -O3 -o %t 
+// RUN: FileCheck --check-prefix=CHECK-TEST1 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-TEST2 %s < %t
+
+#include <typeinfo>
+
+// Test1::A's key function (f) is not defined in this translation unit, but in
+// order to devirtualize calls, we emit the class related data with
+// available_externally linkage.
+
+// CHECK-TEST1: @_ZTVN5Test11AE = available_externally
+// CHECK-TEST1: @_ZTSN5Test11AE = available_externally
+// CHECK-TEST1: @_ZTIN5Test11AE = available_externally
+namespace Test1 {
+
+struct A {
+  A();
+  virtual void f();
+  virtual ~A() { }
+};
+
+A::A() { }
+
+void f(A* a) {
+  a->f();
+};
+
+// CHECK: define void @_ZN5Test11gEv
+// CHECK: call void @_ZN5Test11A1fEv
+void g() {
+  A a;
+  f(&a);
+}
+
+}
+
+// Test2::A's key function (f) is defined in this translation unit, but when
+// we're doing codegen for the typeid(A) call, we don't know that yet.
+// This tests mainly that the typeinfo and typename constants have their linkage
+// updated correctly.
+
+// CHECK-TEST2: @_ZTSN5Test21AE = constant
+// CHECK-TEST2: @_ZTIN5Test21AE = unnamed_addr constant
+// CHECK-TEST2: @_ZTVN5Test21AE = unnamed_addr constant
+namespace Test2 {
+  struct A {
+    virtual void f();
+  };
+
+  const std::type_info &g() {
+    return typeid(A);
+  };
+
+  void A::f() { }
+}





More information about the cfe-commits mailing list