summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2017-01-13 00:43:31 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2017-01-13 00:43:31 +0000
commitfbe2369f1a514423e4c25417ab3532502fde6f2a (patch)
tree3157051db800312a5d48d6210429c2319ceab0ba /clang/lib/CodeGen
parent7150343fbc12648f268cdf352b2aa616a4e771fc (diff)
downloadbcm5719-llvm-fbe2369f1a514423e4c25417ab3532502fde6f2a.tar.gz
bcm5719-llvm-fbe2369f1a514423e4c25417ab3532502fde6f2a.zip
Improve handling of instantiated thread_local variables in Itanium C++ ABI.
* Do not initialize these variables when initializing the rest of the thread_locals in the TU; they have unordered initialization so they can be initialized by themselves. This fixes a rejects-valid bug: we would make the per-variable initializer function internal, but put it in a comdat keyed off the variable, resulting in link errors when the comdat is selected from a different TU (as the per TU TLS init function tries to call an init function that does not exist). * On Darwin, when we decide that we're not going to emit a thread wrapper function at all, demote its linkage to External. Fixes a verifier failure on explicit instantiation of a thread_local variable on Darwin. llvm-svn: 291865
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r--clang/lib/CodeGen/CGDeclCXX.cpp3
-rw-r--r--clang/lib/CodeGen/ItaniumCXXABI.cpp42
2 files changed, 31 insertions, 14 deletions
diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp
index 8d9d0b21bfe..f56e1821693 100644
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/clang/lib/CodeGen/CGDeclCXX.cpp
@@ -353,9 +353,6 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
if (D->getTLSKind()) {
// FIXME: Should we support init_priority for thread_local?
- // FIXME: Ideally, initialization of instantiated thread_local static data
- // members of class templates should not trigger initialization of other
- // entities in the TU.
// FIXME: We only need to register one __cxa_thread_atexit function for the
// entire TU.
CXXThreadLocalInits.push_back(Fn);
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index b5d90ea59a4..f7a8dd66c52 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -2272,7 +2272,21 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs(
ArrayRef<llvm::Function *> CXXThreadLocalInits,
ArrayRef<const VarDecl *> CXXThreadLocalInitVars) {
llvm::Function *InitFunc = nullptr;
- if (!CXXThreadLocalInits.empty()) {
+
+ // Separate initializers into those with ordered (or partially-ordered)
+ // initialization and those with unordered initialization.
+ llvm::SmallVector<llvm::Function *, 8> OrderedInits;
+ llvm::SmallDenseMap<const VarDecl *, llvm::Function *> UnorderedInits;
+ for (unsigned I = 0; I != CXXThreadLocalInits.size(); ++I) {
+ if (isTemplateInstantiation(
+ CXXThreadLocalInitVars[I]->getTemplateSpecializationKind()))
+ UnorderedInits[CXXThreadLocalInitVars[I]->getCanonicalDecl()] =
+ CXXThreadLocalInits[I];
+ else
+ OrderedInits.push_back(CXXThreadLocalInits[I]);
+ }
+
+ if (!OrderedInits.empty()) {
// Generate a guarded initialization function.
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
@@ -2289,24 +2303,28 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs(
CharUnits GuardAlign = CharUnits::One();
Guard->setAlignment(GuardAlign.getQuantity());
- CodeGenFunction(CGM)
- .GenerateCXXGlobalInitFunc(InitFunc, CXXThreadLocalInits,
- Address(Guard, GuardAlign));
+ CodeGenFunction(CGM).GenerateCXXGlobalInitFunc(InitFunc, OrderedInits,
+ Address(Guard, GuardAlign));
// On Darwin platforms, use CXX_FAST_TLS calling convention.
if (CGM.getTarget().getTriple().isOSDarwin()) {
InitFunc->setCallingConv(llvm::CallingConv::CXX_FAST_TLS);
InitFunc->addFnAttr(llvm::Attribute::NoUnwind);
}
}
+
+ // Emit thread wrappers.
for (const VarDecl *VD : CXXThreadLocals) {
llvm::GlobalVariable *Var =
cast<llvm::GlobalVariable>(CGM.GetGlobalValue(CGM.getMangledName(VD)));
+ llvm::Function *Wrapper = getOrCreateThreadLocalWrapper(VD, Var);
// 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())
+ if (isThreadWrapperReplaceable(VD, CGM) && !VD->hasDefinition()) {
+ Wrapper->setLinkage(llvm::Function::ExternalLinkage);
continue;
+ }
// Mangle the name for the thread_local initialization function.
SmallString<256> InitFnName;
@@ -2322,18 +2340,21 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs(
bool InitIsInitFunc = false;
if (VD->hasDefinition()) {
InitIsInitFunc = true;
- if (InitFunc)
+ llvm::Function *InitFuncToUse = InitFunc;
+ if (isTemplateInstantiation(VD->getTemplateSpecializationKind()))
+ InitFuncToUse = UnorderedInits.lookup(VD->getCanonicalDecl());
+ if (InitFuncToUse)
Init = llvm::GlobalAlias::create(Var->getLinkage(), InitFnName.str(),
- InitFunc);
+ InitFuncToUse);
} else {
// Emit a weak global function referring to the initialization function.
// This function will not exist if the TU defining the thread_local
// variable in question does not need any dynamic initialization for
// its thread_local variables.
llvm::FunctionType *FnTy = llvm::FunctionType::get(CGM.VoidTy, false);
- Init = llvm::Function::Create(
- FnTy, llvm::GlobalVariable::ExternalWeakLinkage, InitFnName.str(),
- &CGM.getModule());
+ Init = llvm::Function::Create(FnTy,
+ llvm::GlobalVariable::ExternalWeakLinkage,
+ InitFnName.str(), &CGM.getModule());
const CGFunctionInfo &FI = CGM.getTypes().arrangeNullaryFunction();
CGM.SetLLVMFunctionAttributes(nullptr, FI, cast<llvm::Function>(Init));
}
@@ -2341,7 +2362,6 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs(
if (Init)
Init->setVisibility(Var->getVisibility());
- llvm::Function *Wrapper = getOrCreateThreadLocalWrapper(VD, Var);
llvm::LLVMContext &Context = CGM.getModule().getContext();
llvm::BasicBlock *Entry = llvm::BasicBlock::Create(Context, "", Wrapper);
CGBuilderTy Builder(CGM, Entry);
OpenPOWER on IntegriCloud