r179496 - CodeGen support for function-local static thread_local variables with

Matthieu Monrocq matthieu.monrocq at gmail.com
Mon Apr 15 09:58:58 PDT 2013


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
<richard-llvm at metafoo.co.uk>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
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130415/326a69f0/attachment.html>


More information about the cfe-commits mailing list