diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index 8d9d0b21bfe11..f56e182169311 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 b5d90ea59a498..f7a8dd66c527c 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -2272,7 +2272,21 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs( ArrayRef CXXThreadLocalInits, ArrayRef 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 OrderedInits; + llvm::SmallDenseMap 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(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(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); diff --git a/clang/test/CodeGenCXX/cxx11-thread-local.cpp b/clang/test/CodeGenCXX/cxx11-thread-local.cpp index f465cbdeea847..3231a76ba9208 100644 --- a/clang/test/CodeGenCXX/cxx11-thread-local.cpp +++ b/clang/test/CodeGenCXX/cxx11-thread-local.cpp @@ -6,18 +6,18 @@ int f(); int g(); -// LINUX: @a = thread_local global i32 0 -// DARWIN: @a = internal thread_local global i32 0 +// LINUX-DAG: @a = thread_local global i32 0 +// DARWIN-DAG: @a = internal thread_local global i32 0 thread_local int a = f(); extern thread_local int b; -// CHECK: @c = global i32 0 +// CHECK-DAG: @c = global i32 0 int c = b; -// CHECK: @_ZL1d = internal thread_local global i32 0 +// CHECK-DAG: @_ZL1d = internal thread_local global i32 0 static thread_local int d = g(); struct U { static thread_local int m; }; -// LINUX: @_ZN1U1mE = thread_local global i32 0 -// DARWIN: @_ZN1U1mE = internal thread_local global i32 0 +// LINUX-DAG: @_ZN1U1mE = thread_local global i32 0 +// DARWIN-DAG: @_ZN1U1mE = internal thread_local global i32 0 thread_local int U::m = f(); namespace MismatchedInitType { @@ -35,37 +35,64 @@ namespace MismatchedInitType { template struct V { static thread_local int m; }; template thread_local int V::m = g(); -// CHECK: @e = global i32 0 -int e = V::m; +template struct W { static thread_local int m; }; +template thread_local int W::m = 123; -// CHECK: @_ZN1VIiE1mE = linkonce_odr thread_local global i32 0 +struct Dtor { ~Dtor(); }; +template struct X { static thread_local Dtor m; }; +template thread_local Dtor X::m; -// CHECK: @_ZZ1fvE1n = internal thread_local global i32 0 +// CHECK-DAG: @e = global +void *e = V::m + W::m + &X::m; -// CHECK: @_ZGVZ1fvE1n = internal thread_local global i8 0 +template thread_local int V::m; +template thread_local int W::m; +template thread_local Dtor X::m; -// CHECK: @_ZZ8tls_dtorvE1s = internal thread_local global -// CHECK: @_ZGVZ8tls_dtorvE1s = internal thread_local global i8 0 +extern template thread_local int V::m; +extern template thread_local int W::m; +extern template thread_local Dtor X::m; -// CHECK: @_ZZ8tls_dtorvE1t = internal thread_local global -// CHECK: @_ZGVZ8tls_dtorvE1t = internal thread_local global i8 0 +void *e2 = V::m + W::m + &X::m; -// CHECK: @_ZZ8tls_dtorvE1u = internal thread_local global -// CHECK: @_ZGVZ8tls_dtorvE1u = internal thread_local global i8 0 -// CHECK: @_ZGRZ8tls_dtorvE1u_ = internal thread_local global +// CHECK-DAG: @_ZN1VIiE1mE = linkonce_odr thread_local global i32 0 +// CHECK-DAG: @_ZN1WIiE1mE = linkonce_odr thread_local global i32 123 +// CHECK-DAG: @_ZN1XIiE1mE = linkonce_odr thread_local global {{.*}} +// CHECK-DAG: @_ZN1VIfE1mE = weak_odr thread_local global i32 0 +// CHECK-DAG: @_ZN1WIfE1mE = weak_odr thread_local global i32 123 +// CHECK-DAG: @_ZN1XIfE1mE = weak_odr thread_local global {{.*}} -// CHECK: @_ZGVN1VIiE1mE = linkonce_odr thread_local global i64 0 +// CHECK-DAG: @_ZZ1fvE1n = internal thread_local global i32 0 -// CHECK: @__tls_guard = internal thread_local global i8 0 +// CHECK-DAG: @_ZGVZ1fvE1n = internal thread_local global i8 0 -// CHECK: @llvm.global_ctors = appending global {{.*}} @[[GLOBAL_INIT:[^ ]*]] +// CHECK-DAG: @_ZZ8tls_dtorvE1s = internal thread_local global +// CHECK-DAG: @_ZGVZ8tls_dtorvE1s = internal thread_local global i8 0 -// LINUX: @_ZTH1a = alias void (), void ()* @__tls_init -// DARWIN: @_ZTH1a = internal alias void (), void ()* @__tls_init -// CHECK: @_ZTHL1d = internal alias void (), void ()* @__tls_init -// LINUX: @_ZTHN1U1mE = alias void (), void ()* @__tls_init -// DARWIN: @_ZTHN1U1mE = internal alias void (), void ()* @__tls_init -// CHECK: @_ZTHN1VIiE1mE = linkonce_odr alias void (), void ()* @__tls_init +// CHECK-DAG: @_ZZ8tls_dtorvE1t = internal thread_local global +// CHECK-DAG: @_ZGVZ8tls_dtorvE1t = internal thread_local global i8 0 + +// CHECK-DAG: @_ZZ8tls_dtorvE1u = internal thread_local global +// CHECK-DAG: @_ZGVZ8tls_dtorvE1u = internal thread_local global i8 0 +// CHECK-DAG: @_ZGRZ8tls_dtorvE1u_ = internal thread_local global + +// CHECK-DAG: @_ZGVN1VIiE1mE = linkonce_odr thread_local global i64 0 + +// CHECK-DAG: @__tls_guard = internal thread_local global i8 0 + +// CHECK-DAG: @llvm.global_ctors = appending global {{.*}} @[[GLOBAL_INIT:[^ ]*]] + +// LINUX-DAG: @_ZTH1a = alias void (), void ()* @__tls_init +// DARWIN-DAG: @_ZTH1a = internal alias void (), void ()* @__tls_init +// CHECK-DAG: @_ZTHL1d = internal alias void (), void ()* @__tls_init +// LINUX-DAG: @_ZTHN1U1mE = alias void (), void ()* @__tls_init +// DARWIN-DAG: @_ZTHN1U1mE = internal alias void (), void ()* @__tls_init +// CHECK-DAG: @_ZTHN1VIiE1mE = linkonce_odr alias void (), void ()* @[[V_M_INIT:[^, ]*]] +// CHECK-NOT: @_ZTHN1WIiE1mE = +// CHECK-DAG: @_ZTHN1XIiE1mE = linkonce_odr alias void (), void ()* @[[X_M_INIT:[^, ]*]] +// CHECK-DAG: @_ZTHN1VIfE1mE = weak_odr alias void (), void ()* @[[VF_M_INIT:[^, ]*]] +// CHECK-NOT: @_ZTHN1WIfE1mE = +// CHECK-DAG: @_ZTHN1XIfE1mE = weak_odr alias void (), void ()* @[[XF_M_INIT:[^, ]*]] // Individual variable initialization functions: @@ -118,7 +145,9 @@ int f() { // LINUX: call i32* @_ZTWN1VIiE1mE() // DARWIN: call cxx_fast_tlscc i32* @_ZTWN1VIiE1mE() // CHECK-NEXT: load i32, i32* %{{.*}}, align 4 -// CHECK-NEXT: store i32 %{{.*}}, i32* @e, align 4 +// LINUX: call {{.*}}* @_ZTWN1XIiE1mE() +// DARWIN: call cxx_fast_tlscc {{.*}}* @_ZTWN1XIiE1mE() +// CHECK: store {{.*}} @e // LINUX-LABEL: define weak_odr hidden i32* @_ZTWN1VIiE1mE() // DARWIN-LABEL: define weak_odr hidden cxx_fast_tlscc i32* @_ZTWN1VIiE1mE() @@ -126,6 +155,64 @@ int f() { // DARWIN: call cxx_fast_tlscc void @_ZTHN1VIiE1mE() // CHECK: ret i32* @_ZN1VIiE1mE +// LINUX-LABEL: define weak_odr hidden i32* @_ZTWN1WIiE1mE() +// DARWIN-LABEL: define weak_odr hidden cxx_fast_tlscc i32* @_ZTWN1WIiE1mE() +// CHECK-NOT: call +// CHECK: ret i32* @_ZN1WIiE1mE + +// LINUX-LABEL: define weak_odr hidden {{.*}}* @_ZTWN1XIiE1mE() +// DARWIN-LABEL: define weak_odr hidden cxx_fast_tlscc {{.*}}* @_ZTWN1XIiE1mE() +// LINUX: call void @_ZTHN1XIiE1mE() +// DARWIN: call cxx_fast_tlscc void @_ZTHN1XIiE1mE() +// CHECK: ret {{.*}}* @_ZN1XIiE1mE + +// CHECK: define internal {{.*}} @[[VF_M_INIT]]() +// LINUX-SAME: comdat($_ZN1VIfE1mE) +// DARWIN-NOT: comdat +// CHECK: load i8, i8* bitcast (i64* @_ZGVN1VIfE1mE to i8*) +// CHECK: %[[VF_M_INITIALIZED:.*]] = icmp eq i8 %{{.*}}, 0 +// CHECK: br i1 %[[VF_M_INITIALIZED]], +// need init: +// CHECK: call i32 @_Z1gv() +// CHECK: store i32 %{{.*}}, i32* @_ZN1VIfE1mE, align 4 +// CHECK: store i64 1, i64* @_ZGVN1VIfE1mE +// CHECK: br label + +// CHECK: define internal {{.*}} @[[XF_M_INIT]]() +// LINUX-SAME: comdat($_ZN1XIfE1mE) +// DARWIN-NOT: comdat +// CHECK: load i8, i8* bitcast (i64* @_ZGVN1XIfE1mE to i8*) +// CHECK: %[[XF_M_INITIALIZED:.*]] = icmp eq i8 %{{.*}}, 0 +// CHECK: br i1 %[[XF_M_INITIALIZED]], +// need init: +// LINUX: call {{.*}}__cxa_thread_atexit +// DARWIN: call {{.*}}_tlv_atexit +// CHECK: store i64 1, i64* @_ZGVN1XIfE1mE +// CHECK: br label + +// LINUX: declare i32 @__cxa_thread_atexit(void (i8*)*, i8*, i8*) +// DARWIN: declare i32 @_tlv_atexit(void (i8*)*, i8*, i8*) + +// DARWIN: declare cxx_fast_tlscc i32* @_ZTWN1VIcE1mE() +// LINUX: define weak_odr hidden i32* @_ZTWN1VIcE1mE() +// LINUX-NOT: comdat +// LINUX: br i1 icmp ne (void ()* @_ZTHN1VIcE1mE, +// LINUX: call void @_ZTHN1VIcE1mE() +// LINUX: ret i32* @_ZN1VIcE1mE + +// DARWIN: declare cxx_fast_tlscc i32* @_ZTWN1WIcE1mE() +// LINUX: define weak_odr hidden i32* @_ZTWN1WIcE1mE() +// LINUX-NOT: comdat +// LINUX: br i1 icmp ne (void ()* @_ZTHN1WIcE1mE, +// LINUX: call void @_ZTHN1WIcE1mE() +// LINUX: ret i32* @_ZN1WIcE1mE + +// DARWIN: declare cxx_fast_tlscc {{.*}}* @_ZTWN1XIcE1mE() +// LINUX: define weak_odr hidden {{.*}}* @_ZTWN1XIcE1mE() +// LINUX-NOT: comdat +// LINUX: br i1 icmp ne (void ()* @_ZTHN1XIcE1mE, +// LINUX: call void @_ZTHN1XIcE1mE() +// LINUX: ret {{.*}}* @_ZN1XIcE1mE struct S { S(); ~S(); }; struct T { ~T(); }; @@ -154,9 +241,6 @@ void tls_dtor() { static thread_local const S &u = S(); } -// LINUX: declare i32 @__cxa_thread_atexit(void (i8*)*, i8*, i8*) -// DARWIN: declare i32 @_tlv_atexit(void (i8*)*, i8*, i8*) - // CHECK: define {{.*}} @_Z7PR15991v( int PR15991() { thread_local int n; @@ -184,7 +268,9 @@ void set_anon_i() { // LINUX-LABEL: define internal i32* @_ZTWN12_GLOBAL__N_16anon_iE() // DARWIN-LABEL: define internal cxx_fast_tlscc i32* @_ZTWN12_GLOBAL__N_16anon_iE() -// CHECK: define {{.*}} @[[V_M_INIT:.*]]() +// CHECK: define internal {{.*}} @[[V_M_INIT]]() +// LINUX-SAME: comdat($_ZN1VIiE1mE) +// DARWIN-NOT: comdat // CHECK: load i8, i8* bitcast (i64* @_ZGVN1VIiE1mE to i8*) // CHECK: %[[V_M_INITIALIZED:.*]] = icmp eq i8 %{{.*}}, 0 // CHECK: br i1 %[[V_M_INITIALIZED]], @@ -194,6 +280,18 @@ void set_anon_i() { // CHECK: store i64 1, i64* @_ZGVN1VIiE1mE // CHECK: br label +// CHECK: define internal {{.*}} @[[X_M_INIT]]() +// LINUX-SAME: comdat($_ZN1XIiE1mE) +// DARWIN-NOT: comdat +// CHECK: load i8, i8* bitcast (i64* @_ZGVN1XIiE1mE to i8*) +// CHECK: %[[X_M_INITIALIZED:.*]] = icmp eq i8 %{{.*}}, 0 +// CHECK: br i1 %[[X_M_INITIALIZED]], +// need init: +// LINUX: call {{.*}}__cxa_thread_atexit +// DARWIN: call {{.*}}_tlv_atexit +// CHECK: store i64 1, i64* @_ZGVN1XIiE1mE +// CHECK: br label + // CHECK: define {{.*}}@[[GLOBAL_INIT:.*]]() // CHECK: call void @[[C_INIT]]() // CHECK: call void @[[E_INIT]]() @@ -205,10 +303,13 @@ void set_anon_i() { // CHECK: br i1 %[[NEED_TLS_INIT]], // init: // CHECK: store i8 1, i8* @__tls_guard +// CHECK-NOT: call void @[[V_M_INIT]]() // CHECK: call void @[[A_INIT]]() +// CHECK-NOT: call void @[[V_M_INIT]]() // CHECK: call void @[[D_INIT]]() +// CHECK-NOT: call void @[[V_M_INIT]]() // CHECK: call void @[[U_M_INIT]]() -// CHECK: call void @[[V_M_INIT]]() +// CHECK-NOT: call void @[[V_M_INIT]]() // LIUNX: define weak_odr hidden i32* @_ZTW1a() { diff --git a/clang/test/OpenMP/threadprivate_codegen.cpp b/clang/test/OpenMP/threadprivate_codegen.cpp index 09f5ed5060ba3..318415761ac77 100644 --- a/clang/test/OpenMP/threadprivate_codegen.cpp +++ b/clang/test/OpenMP/threadprivate_codegen.cpp @@ -179,9 +179,9 @@ struct S5 { // CHECK-TLS-DAG: @__dso_handle = external global i8 // CHECK-TLS-DAG: [[GS1_TLS_INIT:@_ZTHL3gs1]] = internal alias void (), void ()* @__tls_init // CHECK-TLS-DAG: [[ARR_X_TLS_INIT:@_ZTH5arr_x]] = alias void (), void ()* @__tls_init -// CHECK-TLS-DAG: [[ST_INT_ST_TLS_INIT:@_ZTHN2STIiE2stE]] = linkonce_odr alias void (), void ()* @__tls_init -// CHECK-TLS-DAG: [[ST_FLOAT_ST_TLS_INIT:@_ZTHN2STIfE2stE]] = linkonce_odr alias void (), void ()* @__tls_init -// CHECK-TLS-DAG: [[ST_S4_ST_TLS_INIT:@_ZTHN2STI2S4E2stE]] = linkonce_odr alias void (), void ()* @__tls_init + + +// CHECK-TLS-DAG: [[ST_S4_ST_TLS_INIT:@_ZTHN2STI2S4E2stE]] = linkonce_odr alias void (), void ()* [[ST_S4_ST_CXX_INIT:@[^, ]*]] struct Static { static S3 s; @@ -640,11 +640,11 @@ int main() { // CHECK-TLS: ret [2 x [3 x [[S1]]]]* [[ARR_X]] // CHECK-TLS: } // CHECK-TLS: define {{.*}} i32* [[ST_INT_ST_TLS_INITD]] {{#[0-9]+}} { -// CHECK-TLS: call void [[ST_INT_ST_TLS_INIT]] +// CHECK-TLS-NOT: call // CHECK-TLS: ret i32* [[ST_INT_ST]] // CHECK-TLS: } // CHECK-TLS: define {{.*}} float* [[ST_FLOAT_ST_TLS_INITD]] {{#[0-9]+}} { -// CHECK-TLS: call void [[ST_FLOAT_ST_TLS_INIT]] +// CHECK-TLS-NOT: call // CHECK-TLS: ret float* [[ST_FLOAT_ST]] // CHECK-TLS: } // CHECK-TLS: define {{.*}} [[S4]]* [[ST_S4_ST_TLS_INITD]] {{#[0-9]+}} { @@ -923,7 +923,7 @@ int foobar() { // CHECK-TLS: define {{.*}}void [[SM_CTOR2]]([[SMAIN]]* {{.*}}, i32 {{.*}}) // CHECK-TLS: define {{.*}}void [[SM_DTOR2]]([[SMAIN]]* {{.*}}) -// CHECK-TLS: define internal void [[ST_S4_ST_CXX_INIT:@.*]]() +// CHECK-TLS: define internal void [[ST_S4_ST_CXX_INIT]]() // CHECK-TLS: call void [[ST_S4_ST_CTOR1:@.*]]([[S4]]* [[ST_S4_ST]], i32 23) // CHECK-TLS: call i32 @__cxa_thread_atexit(void (i8*)* bitcast (void ([[S4]]*)* [[ST_S4_ST_DTOR1:.*]] to void (i8*)*), i8* bitcast ([[S4]]* [[ST_S4_ST]] to i8*) // CHECK-TLS: } @@ -945,7 +945,7 @@ int foobar() { // CHECK-TLS: call void [[GS1_CXX_INIT]] // CHECK-TLS-NOT: call void [[GS2_CXX_INIT]] // CHECK-TLS: call void [[ARR_X_CXX_INIT]] -// CHECK-TLS: call void [[ST_S4_ST_CXX_INIT]] +// CHECK-TLS-NOT: call void [[ST_S4_ST_CXX_INIT]] // CHECK-TLS: [[DONE_LABEL]] // CHECK-TLS-DAG: declare {{.*}} void [[GS3_TLS_INIT]]