Prazek created this revision.
Prazek added reviewers: rsmith, rjmccall, hans, majnemer.
Prazek added a subscriber: cfe-commits.

http://reviews.llvm.org/D12865

Files:
  include/clang/AST/VTableBuilder.h
  lib/CodeGen/CGClass.cpp
  lib/CodeGen/ItaniumCXXABI.cpp
  test/CodeGenCXX/vtable-assume-load.cpp
  test/CodeGenCXX/vtable-available-externally.cpp

Index: test/CodeGenCXX/vtable-available-externally.cpp
===================================================================
--- test/CodeGenCXX/vtable-available-externally.cpp
+++ test/CodeGenCXX/vtable-available-externally.cpp
@@ -11,6 +11,7 @@
 // RUN: FileCheck --check-prefix=CHECK-TEST13 %s < %t.opt
 // RUN: FileCheck --check-prefix=CHECK-TEST14 %s < %t.opt
 // RUN: FileCheck --check-prefix=CHECK-TEST15 %s < %t.opt
+// RUN: FileCheck --check-prefix=CHECK-TEST16 %s < %t.opt
 
 #include <typeinfo>
 
@@ -365,3 +366,28 @@
 }
 }
 
+namespace Test16 {
+// Both classes have methods that are hidden, because of it we can't
+// generate available_externally vtables.
+// CHECK-TEST16-DAG: @_ZTVN6Test161SE = external unnamed_addr constant
+// CHECK-TEST16-DAG: @_ZTVN6Test162S2E = available_externally
+
+struct S {
+  __attribute__((visibility("hidden"))) virtual void doStuff();
+};
+
+struct S2 {
+  virtual void doStuff();
+  __attribute__((visibility("hidden"))) void unused();
+
+};
+
+void test() {
+  S *s = new S;
+  s->doStuff();
+
+  S2 *s2 = new S2;
+  s2->doStuff();
+}
+}
+
Index: test/CodeGenCXX/vtable-assume-load.cpp
===================================================================
--- test/CodeGenCXX/vtable-assume-load.cpp
+++ test/CodeGenCXX/vtable-assume-load.cpp
@@ -9,6 +9,7 @@
 // RUN: FileCheck --check-prefix=CHECK6 --input-file=%t.ll %s
 // RUN: FileCheck --check-prefix=CHECK7 --input-file=%t.ll %s
 // RUN: FileCheck --check-prefix=CHECK8 --input-file=%t.ll %s
+// RUN: FileCheck --check-prefix=CHECK9 --input-file=%t.ll %s
 namespace test1 {
 
 struct A {
@@ -174,19 +175,19 @@
 } // testMS
 
 namespace test6 {
-// CHECK6: @_ZTVN5test61AE = external
 struct A {
   A();
   virtual void foo();
   virtual ~A() {}
 };
 struct B : A {
   B();
 };
-// Because A's vtable is external, it's safe to generate assumption loads.
+// FIXME: Because A's vtable is external, and all functions aint hidden,
+// it's safe to generate assumption loads.
 // CHECK6-LABEL: define void @_ZN5test61gEv()
 // CHECK6: call void @_ZN5test61AC1Ev(
-// CHECK6: call void @llvm.assume(
+// CHECK6-NOT: call void @llvm.assume(
 
 // We can't emit assumption loads for B, because if we would refer to vtable
 // it would refer to functions that will not be able to find (like implicit
@@ -243,7 +244,6 @@
 };
 inline void C::bar() {}
 
-// CHECK8-DAG: @_ZTVN5test81DE = external unnamed_addr constant
 struct D : A {
   D();
   void foo();
@@ -275,8 +275,9 @@
   c.bar();
 }
 
+// FIXME: We could generate assumption loads here.
 // CHECK8-LABEL: define void @_ZN5test81dEv()
-// CHECK8: call void @llvm.assume(
+// CHECK8-NOT: call void @llvm.assume(
 // CHECK8-LABEL: }
 void d() {
   D d;
@@ -291,3 +292,21 @@
   e.bar();
 }
 }
+
+namespace test9 {
+
+struct S {
+  __attribute__((visibility("hidden"))) S();
+  virtual void doStuff();
+};
+
+// CHECK9-LABEL: define void @_ZN5test94testEv()
+// CHECK9-NOT: @llvm.assume(
+// CHECK9: }
+void test() {
+  S *s = new S();
+  s->doStuff();
+  delete s;
+}
+}
+
Index: lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- lib/CodeGen/ItaniumCXXABI.cpp
+++ lib/CodeGen/ItaniumCXXABI.cpp
@@ -386,6 +386,26 @@
     }
     return false;
   }
+
+  bool isVTableHidden(const CXXRecordDecl *RD) const {
+    const auto &VtableLayout =
+            CGM.getItaniumVTableContext().getVTableLayout(RD);
+
+    for (const auto &VtableComponent : VtableLayout.vtable_components()) {
+      if (VtableComponent.isRTTIKind()) {
+        const CXXRecordDecl *RTTIDecl = VtableComponent.getRTTIDecl();
+        if (RTTIDecl->getVisibility() == Visibility::HiddenVisibility)
+          return true;
+      }
+      else if (VtableComponent.isUsedFunctionPointerKind()) {
+        const CXXMethodDecl *Method = VtableComponent.getFunctionDecl();
+        if (Method->getVisibility() == Visibility::HiddenVisibility &&
+            !Method->isDefined())
+          return true;
+      }
+    }
+    return false;
+  }
 };
 
 class ARMCXXABI : public ItaniumCXXABI {
@@ -1615,11 +1635,11 @@
   if (CGM.getLangOpts().AppleKext)
     return false;
 
-  // If we don't have any inline virtual functions,
+  // If we don't have any inline virtual functions, and if vtable is not hidden,
   // then we are safe to emit available_externally copy of vtable.
   // FIXME we can still emit a copy of the vtable if we
   // can emit definition of the inline functions.
-  return !hasAnyUsedVirtualInlineFunction(RD);
+  return !hasAnyUsedVirtualInlineFunction(RD) && !isVTableHidden(RD);
 }
 static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF,
                                           Address InitialPtr,
Index: lib/CodeGen/CGClass.cpp
===================================================================
--- lib/CodeGen/CGClass.cpp
+++ lib/CodeGen/CGClass.cpp
@@ -2036,14 +2036,13 @@
   // first, it's incorrect for classes with virtual bases, and second, we're
   // about to overwrite the vptrs anyway.
   // We also have to make sure if we can refer to vtable:
-  // - If vtable is external then it's safe to use it (for available_externally
-  //   CGVTables will make sure if it can emit it).
   // - Otherwise we can refer to vtable if it's safe to speculatively emit.
-  // FIXME: If vtable is used by ctor/dtor, we are always safe to refer to it.
+  // FIXME: If vtable is used by ctor/dtor, or if vtable is external and we are
+  // sure that definition of vtable is not hidden,
+  // then we are always safe to refer to it.
   if (CGM.getCodeGenOpts().OptimizationLevel > 0 &&
       ClassDecl->isDynamicClass() && Type != Ctor_Base &&
-      (CGM.getVTables().isVTableExternal(ClassDecl) ||
-       CGM.getCXXABI().canSpeculativelyEmitVTable(ClassDecl)))
+      CGM.getCXXABI().canSpeculativelyEmitVTable(ClassDecl))
     EmitVTableAssumptionLoads(ClassDecl, This);
 }
 
Index: include/clang/AST/VTableBuilder.h
===================================================================
--- include/clang/AST/VTableBuilder.h
+++ include/clang/AST/VTableBuilder.h
@@ -122,7 +122,7 @@
   }
 
   const CXXRecordDecl *getRTTIDecl() const {
-    assert(getKind() == CK_RTTI && "Invalid component kind!");
+    assert(isRTTIKind() && "Invalid component kind!");
     return reinterpret_cast<CXXRecordDecl *>(getPointer());
   }
 
@@ -153,6 +153,8 @@
     return isFunctionPointerKind(getKind());
   }
 
+  bool isRTTIKind() const { return isRTTIKind(getKind()); }
+
 private:
   static bool isFunctionPointerKind(Kind ComponentKind) {
     return isUsedFunctionPointerKind(ComponentKind) ||
@@ -166,6 +168,9 @@
     return ComponentKind == CK_CompleteDtorPointer ||
            ComponentKind == CK_DeletingDtorPointer;
   }
+  static bool isRTTIKind(Kind ComponentKind) {
+    return ComponentKind == CK_RTTI;
+  }
 
   VTableComponent(Kind ComponentKind, CharUnits Offset) {
     assert((ComponentKind == CK_VCallOffset ||
@@ -178,7 +183,7 @@
   }
 
   VTableComponent(Kind ComponentKind, uintptr_t Ptr) {
-    assert((ComponentKind == CK_RTTI || isFunctionPointerKind(ComponentKind)) &&
+    assert((isRTTIKind(ComponentKind) || isFunctionPointerKind(ComponentKind)) &&
            "Invalid component kind!");
 
     assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!");
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to