Skip to content

Commit

Permalink
CodeGen: Correct linkage of thread_local for OS X
Browse files Browse the repository at this point in the history
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
  • Loading branch information
majnemer committed Jun 11, 2014
1 parent 1441ef5 commit f64ce12
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 14 deletions.
8 changes: 0 additions & 8 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
10 changes: 10 additions & 0 deletions lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
21 changes: 15 additions & 6 deletions lib/CodeGen/ItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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);
Expand Down
1 change: 1 addition & 0 deletions test/CodeGenCXX/tls-init-funcs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

// CHECK: @a = internal thread_local global
// CHECK: @_tlv_atexit({{.*}}@_ZN1AD1Ev
// CHECK: define weak hidden {{.*}} @_ZTW1a

struct A {
~A();
Expand Down

0 comments on commit f64ce12

Please sign in to comment.