Hi Richard, Does this mean that Clang now has "real" support for thread_local variables ?
Since you seem to be fully implementing this, may we suppose it'll be available (completely) in the 3.3 Release ? -- Matthieu On Mon, Apr 15, 2013 at 1:01 AM, Richard Smith <[email protected]>wrote: > Author: rsmith > Date: Sun Apr 14 18:01:42 2013 > New Revision: 179496 > > URL: http://llvm.org/viewvc/llvm-project?rev=179496&view=rev > Log: > CodeGen support for function-local static thread_local variables with > non-constant constructors or non-trivial destructors. Plus bugfixes for > thread_local references bound to temporaries (the temporaries themselves > are > lifetime-extended to become thread_local), and the corresponding case for > std::initializer_list. > > Added: > cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp > Modified: > cfe/trunk/lib/CodeGen/CGCXXABI.cpp > cfe/trunk/lib/CodeGen/CGCXXABI.h > cfe/trunk/lib/CodeGen/CGDeclCXX.cpp > cfe/trunk/lib/CodeGen/CGExpr.cpp > cfe/trunk/lib/CodeGen/CodeGenModule.cpp > cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp > cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp > cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp > > Modified: cfe/trunk/lib/CodeGen/CGCXXABI.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.cpp?rev=179496&r1=179495&r2=179496&view=diff > > ============================================================================== > --- cfe/trunk/lib/CodeGen/CGCXXABI.cpp (original) > +++ cfe/trunk/lib/CodeGen/CGCXXABI.cpp Sun Apr 14 18:01:42 2013 > @@ -220,8 +220,12 @@ void CGCXXABI::EmitGuardedInit(CodeGenFu > } > > void CGCXXABI::registerGlobalDtor(CodeGenFunction &CGF, > + const VarDecl &D, > llvm::Constant *dtor, > llvm::Constant *addr) { > + if (D.getTLSKind()) > + CGM.ErrorUnsupported(&D, "non-trivial TLS destruction"); > + > // The default behavior is to use atexit. > CGF.registerGlobalDtorWithAtExit(dtor, addr); > } > > Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=179496&r1=179495&r2=179496&view=diff > > ============================================================================== > --- cfe/trunk/lib/CodeGen/CGCXXABI.h (original) > +++ cfe/trunk/lib/CodeGen/CGCXXABI.h Sun Apr 14 18:01:42 2013 > @@ -330,8 +330,8 @@ public: > /// > /// \param dtor - a function taking a single pointer argument > /// \param addr - a pointer to pass to the destructor function. > - virtual void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant > *dtor, > - llvm::Constant *addr); > + virtual void registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D, > + llvm::Constant *dtor, llvm::Constant > *addr); > }; > > // Create an instance of a C++ ABI class: > > Modified: cfe/trunk/lib/CodeGen/CGDeclCXX.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDeclCXX.cpp?rev=179496&r1=179495&r2=179496&view=diff > > ============================================================================== > --- cfe/trunk/lib/CodeGen/CGDeclCXX.cpp (original) > +++ cfe/trunk/lib/CodeGen/CGDeclCXX.cpp Sun Apr 14 18:01:42 2013 > @@ -80,6 +80,7 @@ static void EmitDeclDestroy(CodeGenFunct > case QualType::DK_objc_strong_lifetime: > case QualType::DK_objc_weak_lifetime: > // We don't care about releasing objects during process teardown. > + assert(!D.getTLSKind() && "should have rejected this"); > return; > } > > @@ -105,7 +106,7 @@ static void EmitDeclDestroy(CodeGenFunct > argument = llvm::Constant::getNullValue(CGF.Int8PtrTy); > } > > - CGM.getCXXABI().registerGlobalDtor(CGF, function, argument); > + CGM.getCXXABI().registerGlobalDtor(CGF, D, function, argument); > } > > /// Emit code to cause the variable at the given address to be considered > as > @@ -218,9 +219,6 @@ void CodeGenFunction::EmitCXXGuardedInit > "this initialization requires a guard variable, which " > "the kernel does not support"); > > - if (D.getTLSKind()) > - CGM.ErrorUnsupported(D.getInit(), "dynamic TLS initialization"); > - > CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr, PerformInit); > } > > > Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=179496&r1=179495&r2=179496&view=diff > > ============================================================================== > --- cfe/trunk/lib/CodeGen/CGExpr.cpp (original) > +++ cfe/trunk/lib/CodeGen/CGExpr.cpp Sun Apr 14 18:01:42 2013 > @@ -184,12 +184,16 @@ CreateReferenceTemporary(CodeGenFunction > llvm::Type *RefTempTy = CGF.ConvertTypeForMem(Type); > > // Create the reference temporary. > - llvm::GlobalValue *RefTemp = > + llvm::GlobalVariable *RefTemp = > new llvm::GlobalVariable(CGF.CGM.getModule(), > RefTempTy, /*isConstant=*/false, > llvm::GlobalValue::InternalLinkage, > llvm::Constant::getNullValue(RefTempTy), > Name.str()); > + // If we're binding to a thread_local variable, the temporary is > also > + // thread local. > + if (VD->getTLSKind()) > + CGF.CGM.setTLSMode(RefTemp, *VD); > return RefTemp; > } > } > @@ -434,12 +438,15 @@ CodeGenFunction::EmitReferenceBindingToE > CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, > Dtor_Complete); > CleanupArg = cast<llvm::Constant>(ReferenceTemporary); > } > - CGM.getCXXABI().registerGlobalDtor(*this, CleanupFn, CleanupArg); > + CGM.getCXXABI().registerGlobalDtor(*this, *VD, CleanupFn, > CleanupArg); > } else if (ReferenceInitializerList) { > + // FIXME: This is wrong. We need to register a global destructor to > clean > + // up the initializer_list object, rather than adding it as a local > + // cleanup. > EmitStdInitializerListCleanup(ReferenceTemporary, > ReferenceInitializerList); > } else { > - assert(!ObjCARCReferenceLifetimeType.isNull()); > + assert(!ObjCARCReferenceLifetimeType.isNull() && !VD->getTLSKind()); > // Note: We intentionally do not register a global "destructor" to > // release the object. > } > > Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=179496&r1=179495&r2=179496&view=diff > > ============================================================================== > --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original) > +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Sun Apr 14 18:01:42 2013 > @@ -1627,6 +1627,7 @@ CodeGenModule::MaybeEmitGlobalStdInitial > D->getLocStart(), > D->getLocation(), > name, arrayType, sourceInfo, > SC_Static); > + backingArray->setTLSKind(D->getTLSKind()); > > // Now clone the InitListExpr to initialize the array instead. > // Incredible hack: we want to use the existing InitListExpr here, so > we need > > Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=179496&r1=179495&r2=179496&view=diff > > ============================================================================== > --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original) > +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Sun Apr 14 18:01:42 2013 > @@ -130,8 +130,8 @@ public: > > void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, > llvm::GlobalVariable *DeclPtr, bool PerformInit); > - void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant *dtor, > - llvm::Constant *addr); > + void registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D, > + llvm::Constant *dtor, llvm::Constant *addr); > }; > > class ARMCXXABI : public ItaniumCXXABI { > @@ -1042,10 +1042,10 @@ void ItaniumCXXABI::EmitGuardedInit(Code > bool shouldPerformInit) { > CGBuilderTy &Builder = CGF.Builder; > > - // We only need to use thread-safe statics for local variables; > + // We only need to use thread-safe statics for local non-TLS variables; > // global initialization is always single-threaded. > - bool threadsafe = > - (getContext().getLangOpts().ThreadsafeStatics && D.isLocalVarDecl()); > + bool threadsafe = getContext().getLangOpts().ThreadsafeStatics && > + D.isLocalVarDecl() && !D.getTLSKind(); > > // If we have a global variable with internal linkage and thread-safe > statics > // are disabled, we can just let the guard variable be of type i8. > @@ -1080,6 +1080,8 @@ void ItaniumCXXABI::EmitGuardedInit(Code > llvm::ConstantInt::get(guardTy, 0), > guardName.str()); > guard->setVisibility(var->getVisibility()); > + // If the variable is thread-local, so is its guard variable. > + guard->setThreadLocalMode(var->getThreadLocalMode()); > > CGM.setStaticLocalDeclGuardAddress(&D, guard); > } > @@ -1180,7 +1182,10 @@ void ItaniumCXXABI::EmitGuardedInit(Code > /// Register a global destructor using __cxa_atexit. > static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF, > llvm::Constant *dtor, > - llvm::Constant *addr) { > + llvm::Constant *addr, > + bool TLS) { > + const char *Name = TLS ? "__cxa_thread_atexit" : "__cxa_atexit"; > + > // We're assuming that the destructor function is something we can > // reasonably call with the default CC. Go ahead and cast it to the > // right prototype. > @@ -1193,8 +1198,7 @@ static void emitGlobalDtorWithCXAAtExit( > llvm::FunctionType::get(CGF.IntTy, paramTys, false); > > // Fetch the actual function. > - llvm::Constant *atexit = > - CGF.CGM.CreateRuntimeFunction(atexitTy, "__cxa_atexit"); > + llvm::Constant *atexit = CGF.CGM.CreateRuntimeFunction(atexitTy, Name); > if (llvm::Function *fn = dyn_cast<llvm::Function>(atexit)) > fn->setDoesNotThrow(); > > @@ -1212,12 +1216,15 @@ static void emitGlobalDtorWithCXAAtExit( > > /// Register a global destructor as best as we know how. > void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF, > + const VarDecl &D, > llvm::Constant *dtor, > llvm::Constant *addr) { > // Use __cxa_atexit if available. > - if (CGM.getCodeGenOpts().CXAAtExit) { > - return emitGlobalDtorWithCXAAtExit(CGF, dtor, addr); > - } > + if (CGM.getCodeGenOpts().CXAAtExit) > + return emitGlobalDtorWithCXAAtExit(CGF, dtor, addr, D.getTLSKind()); > + > + if (D.getTLSKind()) > + CGM.ErrorUnsupported(&D, "non-trivial TLS destruction"); > > // In Apple kexts, we want to add a global destructor entry. > // FIXME: shouldn't this be guarded by some variable? > > Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=179496&r1=179495&r2=179496&view=diff > > ============================================================================== > --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original) > +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Sun Apr 14 18:01:42 2013 > @@ -392,6 +392,9 @@ void MicrosoftCXXABI::EmitGuardedInit(Co > // Not sure whether we want thread-safe static local variables as VS > // doesn't make them thread-safe. > > + if (D.getTLSKind()) > + CGM.ErrorUnsupported(&D, "dynamic TLS initialization"); > + > // Emit the initializer and add a global destructor if appropriate. > CGF.EmitCXXGlobalVarDeclInit(D, DeclPtr, PerformInit); > } > > Modified: > cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp?rev=179496&r1=179495&r2=179496&view=diff > > ============================================================================== > --- cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp > (original) > +++ cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp Sun > Apr 14 18:01:42 2013 > @@ -51,6 +51,12 @@ struct wantslist1 { > // CHECK: @globalInitList1 = global %{{[^ ]+}} { i32* getelementptr > inbounds ([3 x i32]* @_ZL25globalInitList1__initlist, i32 0, i32 0), > i{{32|64}} 3 } > std::initializer_list<int> globalInitList1 = {1, 2, 3}; > > +namespace thread_local_global_array { > + // CHECK: @_ZN25thread_local_global_arrayL11x__initlistE = internal > thread_local global [4 x i32] [i32 1, i32 2, i32 3, i32 4] > + // CHECK: @_ZN25thread_local_global_array1xE = thread_local global > {{.*}} @_ZN25thread_local_global_arrayL11x__initlistE, {{.*}} i64 4 > + std::initializer_list<int> thread_local x = { 1, 2, 3, 4 }; > +} > + > // CHECK: @_ZL25globalInitList2__initlist = internal global [2 x %{{[^ > ]*}}] zeroinitializer > // CHECK: @globalInitList2 = global %{{[^ ]+}} { %[[WITHARG:[^ *]+]]* > getelementptr inbounds ([2 x > // CHECK: appending global > > Added: cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp?rev=179496&view=auto > > ============================================================================== > --- cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp (added) > +++ cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp Sun Apr 14 18:01:42 > 2013 > @@ -0,0 +1,56 @@ > +// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple x86_64-linux-gnu > | FileCheck %s > + > +int g(); > + > +// CHECK: @_ZZ1fvE1n = internal thread_local global i32 0 > +// CHECK: @_ZGVZ1fvE1n = internal thread_local global i8 0 > + > +// CHECK: @_ZZ8tls_dtorvE1s = internal thread_local global > +// CHECK: @_ZGVZ8tls_dtorvE1s = internal thread_local global i8 0 > + > +// CHECK: @_ZZ8tls_dtorvE1t = internal thread_local global > +// CHECK: @_ZGVZ8tls_dtorvE1t = internal thread_local global i8 0 > + > +// CHECK: @_ZZ8tls_dtorvE1u = internal thread_local global > +// CHECK: @_ZGVZ8tls_dtorvE1u = internal thread_local global i8 0 > +// CHECK: @_ZGRZ8tls_dtorvE1u = internal thread_local global > + > +// CHECK: define i32 @_Z1fv() > +int f() { > + // CHECK: %[[GUARD:.*]] = load i8* @_ZGVZ1fvE1n, align 1 > + // CHECK: %[[NEED_INIT:.*]] = icmp eq i8 %[[GUARD]], 0 > + // CHECK: br i1 %[[NEED_INIT]] > + > + // CHECK: %[[CALL:.*]] = call i32 @_Z1gv() > + // CHECK: store i32 %[[CALL]], i32* @_ZZ1fvE1n, align 4 > + // CHECK: store i8 1, i8* @_ZGVZ1fvE1n > + // CHECK: br label > + static thread_local int n = g(); > + > + // CHECK: load i32* @_ZZ1fvE1n, align 4 > + return n; > +} > + > +struct S { S(); ~S(); }; > +struct T { ~T(); }; > + > +// CHECK: define void @_Z8tls_dtorv() > +void tls_dtor() { > + // CHECK: load i8* @_ZGVZ8tls_dtorvE1s > + // CHECK: call void @_ZN1SC1Ev(%struct.S* @_ZZ8tls_dtorvE1s) > + // CHECK: call i32 @__cxa_thread_atexit({{.*}}@_ZN1SD1Ev {{.*}} > @_ZZ8tls_dtorvE1s{{.*}} @__dso_handle > + // CHECK: store i8 1, i8* @_ZGVZ8tls_dtorvE1s > + static thread_local S s; > + > + // CHECK: load i8* @_ZGVZ8tls_dtorvE1t > + // CHECK-NOT: _ZN1T > + // CHECK: call i32 @__cxa_thread_atexit({{.*}}@_ZN1TD1Ev > {{.*}}@_ZZ8tls_dtorvE1t{{.*}} @__dso_handle > + // CHECK: store i8 1, i8* @_ZGVZ8tls_dtorvE1t > + static thread_local T t; > + > + // CHECK: load i8* @_ZGVZ8tls_dtorvE1u > + // CHECK: call void @_ZN1SC1Ev(%struct.S* @_ZGRZ8tls_dtorvE1u) > + // CHECK: call i32 @__cxa_thread_atexit({{.*}}@_ZN1SD1Ev {{.*}} > @_ZGRZ8tls_dtorvE1u{{.*}} @__dso_handle > + // CHECK: store i8 1, i8* @_ZGVZ8tls_dtorvE1u > + static thread_local const S &u = S(); > +} > > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
