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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits