]> granicus.if.org Git - clang/commitdiff
CodeGen: Correct linkage of thread_local for OS X
authorDavid Majnemer <david.majnemer@gmail.com>
Wed, 11 Jun 2014 04:08:55 +0000 (04:08 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Wed, 11 Jun 2014 04:08:55 +0000 (04:08 +0000)
The backing store of thread local variables is internal for OS X and all
accesses must go through the thread wrapper.

However, individual TUs may have inlined through the thread wrapper.
To fix this, give the thread wrapper functions WeakAnyLinkage.  This
prevents them from getting inlined into call-sites.

This fixes PR19989.

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

lib/AST/ASTContext.cpp
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/ItaniumCXXABI.cpp
test/CodeGenCXX/tls-init-funcs.cpp

index eaf77e9625445c0f68819f2e35ba1447ab41f675..ddde907522b92bd264181af8332e1d3b2ccc821e 100644 (file)
@@ -7843,14 +7843,6 @@ static GVALinkage basicGVALinkageForVariable(const ASTContext &Context,
                                                : StaticLocalLinkage;
   }
 
-  // On Darwin, the backing variable for a C++11 thread_local variable always
-  // has internal linkage; all accesses should just be calls to the
-  // Itanium-specified entry point, which has the normal linkage of the
-  // variable.
-  if (VD->getTLSKind() == VarDecl::TLS_Dynamic &&
-      Context.getTargetInfo().getTriple().isMacOSX())
-    return GVA_Internal;
-
   switch (VD->getTemplateSpecializationKind()) {
   case TSK_Undeclared:
   case TSK_ExplicitSpecialization:
index b2d87db488006ad42c7bb316317b4e6d07ba7e78..79338787966f03070da3abd6c01ef2b81b32641c 100644 (file)
@@ -1903,6 +1903,16 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
   // Set the llvm linkage type as appropriate.
   llvm::GlobalValue::LinkageTypes Linkage =
       getLLVMLinkageVarDefinition(D, GV->isConstant());
+
+  // On Darwin, the backing variable for a C++11 thread_local variable always
+  // has internal linkage; all accesses should just be calls to the
+  // Itanium-specified entry point, which has the normal linkage of the
+  // variable.
+  if (const auto *VD = dyn_cast<VarDecl>(D))
+    if (!VD->isStaticLocal() && VD->getTLSKind() == VarDecl::TLS_Dynamic &&
+        Context.getTargetInfo().getTriple().isMacOSX())
+      Linkage = llvm::GlobalValue::InternalLinkage;
+
   GV->setLinkage(Linkage);
   if (D->hasAttr<DLLImportAttr>())
     GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass);
index 86eb36d86536946cc71ef7433148102fab5272f8..be8dac140edea58c66423e10b1932c0261c1d965 100644 (file)
@@ -1575,11 +1575,21 @@ void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF,
 /// Get the appropriate linkage for the wrapper function. This is essentially
 /// the weak form of the variable's linkage; every translation unit which wneeds
 /// the wrapper emits a copy, and we want the linker to merge them.
-static llvm::GlobalValue::LinkageTypes getThreadLocalWrapperLinkage(
-    llvm::GlobalValue::LinkageTypes VarLinkage) {
+static llvm::GlobalValue::LinkageTypes
+getThreadLocalWrapperLinkage(const VarDecl *VD, CodeGen::CodeGenModule &CGM) {
+  llvm::GlobalValue::LinkageTypes VarLinkage =
+      CGM.getLLVMLinkageVarDefinition(VD, /*isConstant=*/false);
+
   // For internal linkage variables, we don't need an external or weak wrapper.
   if (llvm::GlobalValue::isLocalLinkage(VarLinkage))
     return VarLinkage;
+
+  // All accesses to the thread_local variable go through the thread wrapper.
+  // However, this means that we cannot allow the thread wrapper to get inlined
+  // into any functions.
+  if (VD->getTLSKind() == VarDecl::TLS_Dynamic &&
+      CGM.getTarget().getTriple().isMacOSX())
+    return llvm::GlobalValue::WeakAnyLinkage;
   return llvm::GlobalValue::WeakODRLinkage;
 }
 
@@ -1602,10 +1612,9 @@ ItaniumCXXABI::getOrCreateThreadLocalWrapper(const VarDecl *VD,
     RetTy = RetTy->getPointerElementType();
 
   llvm::FunctionType *FnTy = llvm::FunctionType::get(RetTy, false);
-  llvm::Function *Wrapper = llvm::Function::Create(
-      FnTy, getThreadLocalWrapperLinkage(
-                CGM.getLLVMLinkageVarDefinition(VD, /*isConstant=*/false)),
-      WrapperName.str(), &CGM.getModule());
+  llvm::Function *Wrapper =
+      llvm::Function::Create(FnTy, getThreadLocalWrapperLinkage(VD, CGM),
+                             WrapperName.str(), &CGM.getModule());
   // Always resolve references to the wrapper at link time.
   if (!Wrapper->hasLocalLinkage())
     Wrapper->setVisibility(llvm::GlobalValue::HiddenVisibility);
index 17299dcb7b6ce753a62197c4d2ebb4189a05ed4e..99fe75f7f4f8398458c80a181dfe1c3380497804 100644 (file)
@@ -2,6 +2,7 @@
 
 // CHECK: @a = internal thread_local global
 // CHECK: @_tlv_atexit({{.*}}@_ZN1AD1Ev
+// CHECK: define weak hidden {{.*}} @_ZTW1a
 
 struct A {
   ~A();