r212841 - CodeGen: Don't emit a thread-wrapper if we can't touch the backing variable

David Majnemer david.majnemer at gmail.com
Fri Jul 11 13:28:10 PDT 2014


Author: majnemer
Date: Fri Jul 11 15:28:10 2014
New Revision: 212841

URL: http://llvm.org/viewvc/llvm-project?rev=212841&view=rev
Log:
CodeGen: Don't emit a thread-wrapper if we can't touch the backing variable

OS X TLS has all accesses going through the thread-wrapper function and
gives the backing thread-local variable internal linkage.  This means
that thread-wrappers must have WeakAnyLinkage so that references to the
internal thread-local variables do not get propagated to other code.

It also means that translation units which do not provide a definition
for the thread-local variable cannot attempt to emit a thread-wrapper
because the thread wrapper will attempt to reference the backing
variable.

Differential Revision: http://reviews.llvm.org/D4109

Modified:
    cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
    cfe/trunk/test/CodeGenCXX/tls-init-funcs.cpp

Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=212841&r1=212840&r2=212841&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Fri Jul 11 15:28:10 2014
@@ -1818,6 +1818,15 @@ void ItaniumCXXABI::registerGlobalDtor(C
   CGF.registerGlobalDtorWithAtExit(D, dtor, addr);
 }
 
+static bool isThreadWrapperReplaceable(const VarDecl *VD,
+                                       CodeGen::CodeGenModule &CGM) {
+  assert(!VD->isStaticLocal() && "static local VarDecls don't need wrappers!");
+  // OS X prefers to have references to thread local variables to go through
+  // the thread wrapper instead of directly referencing the backing variable.
+  return VD->getTLSKind() == VarDecl::TLS_Dynamic &&
+         CGM.getTarget().getTriple().isMacOSX();
+}
+
 /// Get the appropriate linkage for the wrapper function. This is essentially
 /// the weak form of the variable's linkage; every translation unit which needs
 /// the wrapper emits a copy, and we want the linker to merge them.
@@ -1830,12 +1839,13 @@ getThreadLocalWrapperLinkage(const VarDe
   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;
+  // If the thread wrapper is replaceable, give it appropriate linkage.
+  if (isThreadWrapperReplaceable(VD, CGM)) {
+    if (llvm::GlobalVariable::isLinkOnceLinkage(VarLinkage) ||
+        llvm::GlobalVariable::isWeakODRLinkage(VarLinkage))
+      return llvm::GlobalVariable::WeakAnyLinkage;
+    return VarLinkage;
+  }
   return llvm::GlobalValue::WeakODRLinkage;
 }
 
@@ -1862,7 +1872,7 @@ ItaniumCXXABI::getOrCreateThreadLocalWra
       llvm::Function::Create(FnTy, getThreadLocalWrapperLinkage(VD, CGM),
                              WrapperName.str(), &CGM.getModule());
   // Always resolve references to the wrapper at link time.
-  if (!Wrapper->hasLocalLinkage())
+  if (!Wrapper->hasLocalLinkage() && !isThreadWrapperReplaceable(VD, CGM))
     Wrapper->setVisibility(llvm::GlobalValue::HiddenVisibility);
   return Wrapper;
 }
@@ -1874,6 +1884,12 @@ void ItaniumCXXABI::EmitThreadLocalInitF
     const VarDecl *VD = Decls[I].first;
     llvm::GlobalVariable *Var = Decls[I].second;
 
+    // Some targets require that all access to thread local variables go through
+    // the thread wrapper.  This means that we cannot attempt to create a thread
+    // wrapper or a thread helper.
+    if (isThreadWrapperReplaceable(VD, CGM) && !VD->hasDefinition())
+      continue;
+
     // Mangle the name for the thread_local initialization function.
     SmallString<256> InitFnName;
     {

Modified: cfe/trunk/test/CodeGenCXX/tls-init-funcs.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/tls-init-funcs.cpp?rev=212841&r1=212840&r2=212841&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/tls-init-funcs.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/tls-init-funcs.cpp Fri Jul 11 15:28:10 2014
@@ -1,11 +1,34 @@
-// RUN: %clang_cc1 -triple x86_64-apple-macosx10.8 -std=c++11 -S -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.8 -std=c++1y -S -emit-llvm %s -o - | FileCheck %s
 
 // CHECK: @a = internal thread_local global
+// CHECK: @_Z2vtIiE = internal thread_local global i32 5
+// CHECK: @_ZZ3inlvE3loc = linkonce_odr thread_local global i32 0
 // CHECK: @_tlv_atexit({{.*}}@_ZN1AD1Ev
-// CHECK: define weak hidden {{.*}} @_ZTW1a
+// CHECK: call i32* @_ZTW3ext()
+// CHECK: declare i32* @_ZTW3ext()
+// CHECK: define weak i32* @_ZTW2vtIiE()
+// CHECK: define weak i32* @_ZTW2vtIvE()
+// CHECK: define {{.*}} @_ZTW1a
 
 struct A {
   ~A();
 };
 
 thread_local A a;
+
+extern thread_local int ext;
+int &get_ext() { return ext; }
+
+template <typename T>
+thread_local int vt = 5;
+
+int get_vt() { return vt<int>; }
+
+inline int &inl() {
+  thread_local int loc;
+  return loc;
+}
+int &use_inl() { return inl(); }
+
+template int vt<void>;
+int &get_vt_void() { return vt<void>; }





More information about the cfe-commits mailing list