]> granicus.if.org Git - clang/commitdiff
Extend the visibility-hidden optimization to linkonce_odr thunks for
authorJohn McCall <rjmccall@apple.com>
Wed, 4 Aug 2010 23:46:35 +0000 (23:46 +0000)
committerJohn McCall <rjmccall@apple.com>
Wed, 4 Aug 2010 23:46:35 +0000 (23:46 +0000)
functions with in-line definitions, since such thunks will be emitted at any
use of the function.

Completes the feature work for rdar://problem/7523229.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@110285 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGVTables.cpp
test/CodeGenCXX/thunks.cpp

index db405d3673ae3a864daf69ad1e05849ca1b892a1..cd34d03cd7747a5048c1b7c0934fa96b26d62806 100644 (file)
@@ -2460,6 +2460,56 @@ static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF,
   return CGF.Builder.CreateBitCast(V, Ptr->getType());
 }
 
+static void setThunkVisibility(CodeGenModule &CGM, const CXXMethodDecl *MD,
+                               const ThunkInfo &Thunk, llvm::Function *Fn) {
+  CGM.setGlobalVisibility(Fn, MD);
+
+  // If the thunk has weak/linkonce linkage, but the function must be
+  // emitted in every translation unit that references it, then we can
+  // emit its thunks with hidden visibility, since its thunks must be
+  // emitted when the function is.
+
+  // This mostly follows CodeGenModule::setTypeVisibility.
+
+  if ((Fn->getLinkage() != llvm::GlobalVariable::LinkOnceODRLinkage &&
+       Fn->getLinkage() != llvm::GlobalVariable::WeakODRLinkage) ||
+      Fn->getVisibility() != llvm::GlobalVariable::DefaultVisibility)
+    return;
+
+  // Don't override an explicit visibility attribute.
+  if (MD->hasAttr<VisibilityAttr>())
+    return;
+
+  switch (MD->getTemplateSpecializationKind()) {
+  // We have to disable the optimization if this is an EI definition
+  // because there might be EI declarations in other shared objects.
+  case TSK_ExplicitInstantiationDefinition:
+  case TSK_ExplicitInstantiationDeclaration:
+    return;
+
+  // Every use of a non-template or explicitly-specialized class's
+  // type information has to emit it.
+  case TSK_ExplicitSpecialization:
+  case TSK_Undeclared:
+    break;
+
+  // Implicit instantiations can ignore the possibility of an
+  // explicit instantiation declaration because there necessarily
+  // must be an EI definition somewhere with default visibility.
+  case TSK_ImplicitInstantiation:
+    break;
+  }
+
+  // If there's an explicit definition, and that definition is
+  // out-of-line, then we can't assume that all users will have a
+  // definition to emit.
+  const FunctionDecl *Def = 0;
+  if (MD->hasBody(Def) && Def->isOutOfLine())
+    return;
+
+  Fn->setVisibility(llvm::GlobalValue::HiddenVisibility);
+}
+
 void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD,
                                     const ThunkInfo &Thunk) {
   const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
@@ -2582,7 +2632,7 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD,
   CGM.setFunctionLinkage(MD, Fn);
   
   // Set the right visibility.
-  CGM.setGlobalVisibility(Fn, MD);
+  setThunkVisibility(CGM, MD, Thunk, Fn);
 }
 
 void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk)
index 1de576128a11d2a7832d5e57a1283fa2a98fca64..5ecaacb16a9e6ef8dc44986c4ea61e846c166c72 100644 (file)
@@ -246,8 +246,21 @@ namespace Test9 {
   }
 }
 
+namespace Test10 {
+  struct A { virtual void foo(); };
+  struct B { virtual void foo(); };
+  struct C : A, B { void foo() {} };
+
+  // CHECK: define linkonce_odr void @_ZN6Test101C3fooEv
+  // CHECK: define linkonce_odr hidden void @_ZThn8_N6Test101C3fooEv
+
+  void test() {
+    C c;
+  }
+}
+
 /**** The following has to go at the end of the file ****/
 
 // This is from Test5:
-// CHECK: define linkonce_odr void @_ZTv0_n24_N5Test51B1fEv
+// CHECK: define linkonce_odr hidden void @_ZTv0_n24_N5Test51B1fEv
 // CHECK: define internal void @_ZThn8_N12_GLOBAL__N_11C1fEv(