r179858 - Implement CodeGen for C++11 thread_local, following the Itanium ABI specification as discussed on cxx-abi-dev.

Richard Smith richard-llvm at metafoo.co.uk
Fri Apr 19 09:42:07 PDT 2013


Author: rsmith
Date: Fri Apr 19 11:42:07 2013
New Revision: 179858

URL: http://llvm.org/viewvc/llvm-project?rev=179858&view=rev
Log:
Implement CodeGen for C++11 thread_local, following the Itanium ABI specification as discussed on cxx-abi-dev.

Added:
    cfe/trunk/test/CodeGenCXX/cxx11-thread-local-reference.cpp
Modified:
    cfe/trunk/include/clang/AST/Mangle.h
    cfe/trunk/lib/AST/ItaniumMangle.cpp
    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/CodeGenFunction.h
    cfe/trunk/lib/CodeGen/CodeGenModule.cpp
    cfe/trunk/lib/CodeGen/CodeGenModule.h
    cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
    cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp

Modified: cfe/trunk/include/clang/AST/Mangle.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Mangle.h?rev=179858&r1=179857&r2=179858&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Mangle.h (original)
+++ cfe/trunk/include/clang/AST/Mangle.h Fri Apr 19 11:42:07 2013
@@ -141,6 +141,16 @@ public:
                                           raw_ostream &) {
     llvm_unreachable("Target does not support mangling guard variables");
   }
+  // FIXME: Revisit this once we know what we need to do for MSVC compatibility.
+  virtual void mangleItaniumThreadLocalInit(const VarDecl *D,
+                                            raw_ostream &) {
+    llvm_unreachable("Target does not support mangling thread_local variables");
+  }
+  virtual void mangleItaniumThreadLocalWrapper(const VarDecl *D,
+                                               raw_ostream &) {
+    llvm_unreachable("Target does not support mangling thread_local variables");
+  }
+
   /// @}
 };
 

Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=179858&r1=179857&r2=179858&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)
+++ cfe/trunk/lib/AST/ItaniumMangle.cpp Fri Apr 19 11:42:07 2013
@@ -141,6 +141,8 @@ public:
                      raw_ostream &);
 
   void mangleItaniumGuardVariable(const VarDecl *D, raw_ostream &);
+  void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &);
+  void mangleItaniumThreadLocalWrapper(const VarDecl *D, raw_ostream &);
 
   void mangleInitDiscriminator() {
     Discriminator = 0;
@@ -3531,6 +3533,22 @@ void ItaniumMangleContext::mangleItanium
   Mangler.mangleName(D);
 }
 
+void ItaniumMangleContext::mangleItaniumThreadLocalInit(const VarDecl *D,
+                                                        raw_ostream &Out) {
+  //  <special-name> ::= TH <object name>
+  CXXNameMangler Mangler(*this, Out);
+  Mangler.getStream() << "_ZTH";
+  Mangler.mangleName(D);
+}
+
+void ItaniumMangleContext::mangleItaniumThreadLocalWrapper(const VarDecl *D,
+                                                           raw_ostream &Out) {
+  //  <special-name> ::= TW <object name>
+  CXXNameMangler Mangler(*this, Out);
+  Mangler.getStream() << "_ZTW";
+  Mangler.mangleName(D);
+}
+
 void ItaniumMangleContext::mangleReferenceTemporary(const VarDecl *D,
                                                     raw_ostream &Out) {
   // We match the GCC mangling here.

Modified: cfe/trunk/lib/CodeGen/CGCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.cpp?rev=179858&r1=179857&r2=179858&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.cpp Fri Apr 19 11:42:07 2013
@@ -259,3 +259,14 @@ llvm::BasicBlock *CGCXXABI::EmitCtorComp
   ErrorUnsupportedABI(CGF, "complete object detection in ctor");
   return 0;
 }
+
+void CGCXXABI::EmitThreadLocalInitFuncs(
+    llvm::ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls,
+    llvm::Function *InitFunc) {
+}
+
+LValue CGCXXABI::EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF,
+                                          const DeclRefExpr *DRE) {
+  ErrorUnsupportedABI(CGF, "odr-use of thread_local global");
+  return LValue();
+}

Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=179858&r1=179857&r2=179858&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.h Fri Apr 19 11:42:07 2013
@@ -353,6 +353,25 @@ public:
   /// \param addr - a pointer to pass to the destructor function.
   virtual void registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
                                   llvm::Constant *dtor, llvm::Constant *addr);
+
+  /*************************** thread_local initialization ********************/
+
+  /// Emits ABI-required functions necessary to initialize thread_local
+  /// variables in this translation unit.
+  ///
+  /// \param Decls The thread_local declarations in this translation unit.
+  /// \param InitFunc If this translation unit contains any non-constant
+  ///        initialization or non-trivial destruction for thread_local
+  ///        variables, a function to perform the initialization. Otherwise, 0.
+  virtual void EmitThreadLocalInitFuncs(
+      llvm::ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls,
+      llvm::Function *InitFunc);
+
+  /// Emit a reference to a non-local thread_local variable (including
+  /// triggering the initialization of all thread_local variables in its
+  /// translation unit).
+  virtual LValue EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF,
+                                            const DeclRefExpr *DRE);
 };
 
 // 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=179858&r1=179857&r2=179858&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDeclCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDeclCXX.cpp Fri Apr 19 11:42:07 2013
@@ -156,7 +156,8 @@ void CodeGenFunction::EmitCXXGlobalVarDe
 static llvm::Function *
 CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
                                    llvm::FunctionType *ty,
-                                   const Twine &name);
+                                   const Twine &name,
+                                   bool TLS = false);
 
 /// Create a stub function, suitable for being passed to atexit,
 /// which passes the given address to the given destructor function.
@@ -225,11 +226,11 @@ void CodeGenFunction::EmitCXXGuardedInit
 static llvm::Function *
 CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
                                    llvm::FunctionType *FTy,
-                                   const Twine &Name) {
+                                   const Twine &Name, bool TLS) {
   llvm::Function *Fn =
     llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
                            Name, &CGM.getModule());
-  if (!CGM.getLangOpts().AppleKext) {
+  if (!CGM.getLangOpts().AppleKext && !TLS) {
     // Set the section if needed.
     if (const char *Section = 
           CGM.getTarget().getStaticInitSectionSpecifier())
@@ -255,9 +256,6 @@ void
 CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
                                             llvm::GlobalVariable *Addr,
                                             bool PerformInit) {
-  if (D->getTLSKind())
-    ErrorUnsupported(D->getInit(), "dynamic TLS initialization");
-
   llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
 
   // Create a variable initialization function.
@@ -267,12 +265,20 @@ CodeGenModule::EmitCXXGlobalVarDeclInitF
   CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr,
                                                           PerformInit);
 
-  if (D->hasAttr<InitPriorityAttr>()) {
+  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);
+  } else if (D->hasAttr<InitPriorityAttr>()) {
     unsigned int order = D->getAttr<InitPriorityAttr>()->getPriority();
     OrderGlobalInits Key(order, PrioritizedCXXGlobalInits.size());
     PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn));
     DelayedCXXInitPosition.erase(D);
-  }  else {
+  } else {
     llvm::DenseMap<const Decl *, unsigned>::iterator I =
       DelayedCXXInitPosition.find(D);
     if (I == DelayedCXXInitPosition.end()) {
@@ -285,6 +291,27 @@ CodeGenModule::EmitCXXGlobalVarDeclInitF
   }
 }
 
+void CodeGenModule::EmitCXXThreadLocalInitFunc() {
+  llvm::Function *InitFn = 0;
+  if (!CXXThreadLocalInits.empty()) {
+    // Generate a guarded initialization function.
+    llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
+    InitFn = CreateGlobalInitOrDestructFunction(
+        *this, FTy, "__tls_init", /*TLS*/ true);
+    llvm::GlobalVariable *Guard = new llvm::GlobalVariable(
+        getModule(), Int8Ty, false, llvm::GlobalVariable::InternalLinkage,
+        llvm::ConstantInt::get(Int8Ty, 0), "__tls_guard");
+    Guard->setThreadLocal(true);
+    CodeGenFunction(*this).GenerateCXXGlobalInitFunc(
+        InitFn, CXXThreadLocalInits.data(), CXXThreadLocalInits.size(), Guard);
+  }
+
+  getCXXABI().EmitThreadLocalInitFuncs(CXXThreadLocals, InitFn);
+
+  CXXThreadLocalInits.clear();
+  CXXThreadLocals.clear();
+}
+
 void
 CodeGenModule::EmitCXXGlobalInitFunc() {
   while (!CXXGlobalInits.empty() && !CXXGlobalInits.back())
@@ -385,7 +412,8 @@ void CodeGenFunction::GenerateCXXGlobalV
 
 void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
                                                 llvm::Constant **Decls,
-                                                unsigned NumDecls) {
+                                                unsigned NumDecls,
+                                                llvm::GlobalVariable *Guard) {
   // Initialize debug info if needed.
   maybeInitializeDebugInfo();
 
@@ -393,6 +421,22 @@ void CodeGenFunction::GenerateCXXGlobalI
                 getTypes().arrangeNullaryFunction(),
                 FunctionArgList(), SourceLocation());
 
+  llvm::BasicBlock *ExitBlock = 0;
+  if (Guard) {
+    // If we have a guard variable, check whether we've already performed these
+    // initializations. This happens for TLS initialization functions.
+    llvm::Value *GuardVal = Builder.CreateLoad(Guard);
+    llvm::Value *Uninit = Builder.CreateIsNull(GuardVal, "guard.uninitialized");
+    // Mark as initialized before initializing anything else. If the
+    // initializers use previously-initialized thread_local vars, that's
+    // probably supposed to be OK, but the standard doesn't say.
+    Builder.CreateStore(llvm::ConstantInt::get(GuardVal->getType(), 1), Guard);
+    llvm::BasicBlock *InitBlock = createBasicBlock("init");
+    ExitBlock = createBasicBlock("exit");
+    Builder.CreateCondBr(Uninit, InitBlock, ExitBlock);
+    EmitBlock(InitBlock);
+  }
+
   RunCleanupsScope Scope(*this);
 
   // When building in Objective-C++ ARC mode, create an autorelease pool
@@ -407,7 +451,12 @@ void CodeGenFunction::GenerateCXXGlobalI
       EmitRuntimeCall(Decls[i]);
 
   Scope.ForceCleanup();
-  
+
+  if (ExitBlock) {
+    Builder.CreateBr(ExitBlock);
+    EmitBlock(ExitBlock);
+  }
+
   FinishFunction();
 }
 

Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=179858&r1=179857&r2=179858&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Fri Apr 19 11:42:07 2013
@@ -1824,8 +1824,12 @@ LValue CodeGenFunction::EmitDeclRefLValu
 
   if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
     // Check if this is a global variable.
-    if (VD->hasLinkage() || VD->isStaticDataMember())
+    if (VD->hasLinkage() || VD->isStaticDataMember()) {
+      // If it's thread_local, emit a call to its wrapper function instead.
+      if (VD->getTLSKind() == VarDecl::TLS_Dynamic)
+        return CGM.getCXXABI().EmitThreadLocalDeclRefExpr(*this, E);
       return EmitGlobalVarDeclLValue(*this, E, VD);
+    }
 
     bool isBlockVariable = VD->hasAttr<BlocksAttr>();
 

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=179858&r1=179857&r2=179858&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Fri Apr 19 11:42:07 2013
@@ -2628,7 +2628,8 @@ public:
   /// variables.
   void GenerateCXXGlobalInitFunc(llvm::Function *Fn,
                                  llvm::Constant **Decls,
-                                 unsigned NumDecls);
+                                 unsigned NumDecls,
+                                 llvm::GlobalVariable *Guard = 0);
 
   /// GenerateCXXGlobalDtorsFunc - Generates code for destroying global
   /// variables.

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=179858&r1=179857&r2=179858&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Fri Apr 19 11:42:07 2013
@@ -176,6 +176,7 @@ void CodeGenModule::Release() {
   EmitDeferred();
   EmitCXXGlobalInitFunc();
   EmitCXXGlobalDtorFunc();
+  EmitCXXThreadLocalInitFunc();
   if (ObjCRuntime)
     if (llvm::Function *ObjCInitFunction = ObjCRuntime->ModuleInitFunction())
       AddGlobalCtor(ObjCInitFunction);
@@ -1477,8 +1478,10 @@ CodeGenModule::GetOrCreateLLVMGlobal(Str
         GV->setVisibility(GetLLVMVisibility(LV.getVisibility()));
     }
 
-    if (D->getTLSKind())
+    if (D->getTLSKind()) {
+      CXXThreadLocals.push_back(std::make_pair(D, GV));
       setTLSMode(GV, *D);
+    }
   }
 
   if (AddrSpace != Ty->getAddressSpace())

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=179858&r1=179857&r2=179858&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.h Fri Apr 19 11:42:07 2013
@@ -317,6 +317,14 @@ class CodeGenModule : public CodeGenType
                           llvm::GlobalValue *> StaticExternCMap;
   StaticExternCMap StaticExternCValues;
 
+  /// \brief thread_local variables defined or used in this TU.
+  std::vector<std::pair<const VarDecl *, llvm::GlobalVariable *> >
+    CXXThreadLocals;
+
+  /// \brief thread_local variables with initializers that need to run
+  /// before any thread_local variable in this TU is odr-used.
+  std::vector<llvm::Constant*> CXXThreadLocalInits;
+
   /// CXXGlobalInits - Global variables with initializers that need to run
   /// before main.
   std::vector<llvm::Constant*> CXXGlobalInits;
@@ -1026,6 +1034,9 @@ private:
   /// a C++ destructor Decl.
   void EmitCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type);
 
+  /// \brief Emit the function that initializes C++ thread_local variables.
+  void EmitCXXThreadLocalInitFunc();
+
   /// EmitCXXGlobalInitFunc - Emit the function that initializes C++ globals.
   void EmitCXXGlobalInitFunc();
 

Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=179858&r1=179857&r2=179858&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Fri Apr 19 11:42:07 2013
@@ -146,6 +146,14 @@ public:
                        llvm::GlobalVariable *DeclPtr, bool PerformInit);
   void registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
                           llvm::Constant *dtor, llvm::Constant *addr);
+
+  llvm::Function *getOrCreateThreadLocalWrapper(const VarDecl *VD,
+                                                llvm::GlobalVariable *Var);
+  void EmitThreadLocalInitFuncs(
+      llvm::ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls,
+      llvm::Function *InitFunc);
+  LValue EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF,
+                                    const DeclRefExpr *DRE);
 };
 
 class ARMCXXABI : public ItaniumCXXABI {
@@ -1249,3 +1257,138 @@ void ItaniumCXXABI::registerGlobalDtor(C
 
   CGF.registerGlobalDtorWithAtExit(dtor, addr);
 }
+
+/// 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) {
+  if (llvm::GlobalValue::isLinkerPrivateLinkage(VarLinkage))
+    return llvm::GlobalValue::LinkerPrivateWeakLinkage;
+  // For internal linkage variables, we don't need an external or weak wrapper.
+  if (llvm::GlobalValue::isLocalLinkage(VarLinkage))
+    return VarLinkage;
+  return llvm::GlobalValue::WeakODRLinkage;
+}
+
+llvm::Function *
+ItaniumCXXABI::getOrCreateThreadLocalWrapper(const VarDecl *VD,
+                                             llvm::GlobalVariable *Var) {
+  // Mangle the name for the thread_local wrapper function.
+  SmallString<256> WrapperName;
+  {
+    llvm::raw_svector_ostream Out(WrapperName);
+    getMangleContext().mangleItaniumThreadLocalWrapper(VD, Out);
+    Out.flush();
+  }
+
+  if (llvm::Value *V = Var->getParent()->getNamedValue(WrapperName))
+    return cast<llvm::Function>(V);
+
+  llvm::Type *RetTy = Var->getType();
+  if (VD->getType()->isReferenceType())
+    RetTy = RetTy->getPointerElementType();
+
+  llvm::FunctionType *FnTy = llvm::FunctionType::get(RetTy, false);
+  llvm::Function *Wrapper = llvm::Function::Create(
+      FnTy, getThreadLocalWrapperLinkage(Var->getLinkage()), WrapperName.str(),
+      &CGM.getModule());
+  // Always resolve references to the wrapper at link time.
+  Wrapper->setVisibility(llvm::GlobalValue::HiddenVisibility);
+  return Wrapper;
+}
+
+void ItaniumCXXABI::EmitThreadLocalInitFuncs(
+    llvm::ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls,
+    llvm::Function *InitFunc) {
+  for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
+    const VarDecl *VD = Decls[I].first;
+    llvm::GlobalVariable *Var = Decls[I].second;
+
+    // Mangle the name for the thread_local initialization function.
+    SmallString<256> InitFnName;
+    {
+      llvm::raw_svector_ostream Out(InitFnName);
+      getMangleContext().mangleItaniumThreadLocalInit(VD, Out);
+      Out.flush();
+    }
+
+    // If we have a definition for the variable, emit the initialization
+    // function as an alias to the global Init function (if any). Otherwise,
+    // produce a declaration of the initialization function.
+    llvm::GlobalValue *Init = 0;
+    bool InitIsInitFunc = false;
+    if (VD->hasDefinition()) {
+      InitIsInitFunc = true;
+      if (InitFunc)
+        Init =
+            new llvm::GlobalAlias(InitFunc->getType(), Var->getLinkage(),
+                                  InitFnName.str(), InitFunc, &CGM.getModule());
+    } 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());
+    }
+
+    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(Entry);
+    if (InitIsInitFunc) {
+      if (Init)
+        Builder.CreateCall(Init);
+    } else {
+      // Don't know whether we have an init function. Call it if it exists.
+      llvm::Value *Have = Builder.CreateIsNotNull(Init);
+      llvm::BasicBlock *InitBB = llvm::BasicBlock::Create(Context, "", Wrapper);
+      llvm::BasicBlock *ExitBB = llvm::BasicBlock::Create(Context, "", Wrapper);
+      Builder.CreateCondBr(Have, InitBB, ExitBB);
+
+      Builder.SetInsertPoint(InitBB);
+      Builder.CreateCall(Init);
+      Builder.CreateBr(ExitBB);
+
+      Builder.SetInsertPoint(ExitBB);
+    }
+
+    // For a reference, the result of the wrapper function is a pointer to
+    // the referenced object.
+    llvm::Value *Val = Var;
+    if (VD->getType()->isReferenceType()) {
+      llvm::LoadInst *LI = Builder.CreateLoad(Val);
+      LI->setAlignment(CGM.getContext().getDeclAlign(VD).getQuantity());
+      Val = LI;
+    }
+
+    Builder.CreateRet(Val);
+  }
+}
+
+LValue ItaniumCXXABI::EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF,
+                                                 const DeclRefExpr *DRE) {
+  const VarDecl *VD = cast<VarDecl>(DRE->getDecl());
+  QualType T = VD->getType();
+  llvm::Type *Ty = CGF.getTypes().ConvertTypeForMem(T);
+  llvm::Value *Val = CGF.CGM.GetAddrOfGlobalVar(VD, Ty);
+  llvm::Function *Wrapper =
+      getOrCreateThreadLocalWrapper(VD, cast<llvm::GlobalVariable>(Val));
+
+  Val = CGF.Builder.CreateCall(Wrapper);
+
+  LValue LV;
+  if (VD->getType()->isReferenceType())
+    LV = CGF.MakeNaturalAlignAddrLValue(Val, T);
+  else
+    LV = CGF.MakeAddrLValue(Val, DRE->getType(),
+                            CGF.getContext().getDeclAlign(VD));
+  // FIXME: need setObjCGCLValueClass?
+  return LV;
+}

Added: cfe/trunk/test/CodeGenCXX/cxx11-thread-local-reference.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx11-thread-local-reference.cpp?rev=179858&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx11-thread-local-reference.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/cxx11-thread-local-reference.cpp Fri Apr 19 11:42:07 2013
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
+
+int &f();
+
+// CHECK: @r = thread_local global i32* null
+thread_local int &r = f();
+
+// CHECK: @_ZTH1r = alias void ()* @__tls_init
+
+int &g() { return r; }
+
+// CHECK: define {{.*}} @[[R_INIT:.*]]()
+// CHECK: call i32* @_Z1fv()
+// CHECK: store i32* %{{.*}}, i32** @r, align 8
+
+// CHECK: define i32* @_Z1gv()
+// CHECK: call i32* @_ZTW1r()
+// CHECK: ret i32* %{{.*}}
+
+// CHECK: define weak_odr hidden i32* @_ZTW1r() {
+// CHECK: call void @_ZTH1r()
+// CHECK: load i32** @r, align 8
+// CHECK: ret i32* %{{.*}}
+
+// CHECK: define internal void @__tls_init()
+// CHECK: call void @[[R_INIT]]()

Modified: cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp?rev=179858&r1=179857&r2=179858&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp Fri Apr 19 11:42:07 2013
@@ -1,8 +1,30 @@
 // RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
 
+int f();
 int g();
 
+// CHECK: @a = thread_local global i32 0
+thread_local int a = f();
+extern thread_local int b;
+// CHECK: @c = global i32 0
+int c = b;
+// CHECK: @_ZL1d = internal thread_local global i32 0
+static thread_local int d = g();
+
+struct U { static thread_local int m; };
+// CHECK: @_ZN1U1mE = thread_local global i32 0
+thread_local int U::m = f();
+
+template<typename T> struct V { static thread_local int m; };
+template<typename T> thread_local int V<T>::m = g();
+
+// CHECK: @e = global i32 0
+int e = V<int>::m;
+
+// CHECK: @_ZN1VIiE1mE = weak_odr thread_local global i32 0
+
 // CHECK: @_ZZ1fvE1n = internal thread_local global i32 0
+
 // CHECK: @_ZGVZ1fvE1n = internal thread_local global i8 0
 
 // CHECK: @_ZZ8tls_dtorvE1s = internal thread_local global
@@ -15,6 +37,24 @@ int g();
 // CHECK: @_ZGVZ8tls_dtorvE1u = internal thread_local global i8 0
 // CHECK: @_ZGRZ8tls_dtorvE1u = internal thread_local global
 
+// CHECK: @_ZGVN1VIiE1mE = weak_odr thread_local global i64 0
+
+// CHECK: @__tls_guard = internal thread_local global i8 0
+
+// CHECK: @llvm.global_ctors = appending global {{.*}} @[[GLOBAL_INIT:[^ ]*]]
+
+// CHECK: @_ZTH1a = alias void ()* @__tls_init
+// CHECK: @_ZTHL1d = alias internal void ()* @__tls_init
+// CHECK: @_ZTHN1U1mE = alias void ()* @__tls_init
+// CHECK: @_ZTHN1VIiE1mE = alias weak_odr void ()* @__tls_init
+
+
+// Individual variable initialization functions:
+
+// CHECK: define {{.*}} @[[A_INIT:.*]]()
+// CHECK: call i32 @_Z1fv()
+// CHECK-NEXT: store i32 {{.*}}, i32* @a, align 4
+
 // CHECK: define i32 @_Z1fv()
 int f() {
   // CHECK: %[[GUARD:.*]] = load i8* @_ZGVZ1fvE1n, align 1
@@ -31,6 +71,37 @@ int f() {
   return n;
 }
 
+// CHECK: define {{.*}} @[[C_INIT:.*]]()
+// CHECK: call i32* @_ZTW1b()
+// CHECK-NEXT: load i32* %{{.*}}, align 4
+// CHECK-NEXT: store i32 %{{.*}}, i32* @c, align 4
+
+// CHECK: define weak_odr hidden i32* @_ZTW1b()
+// CHECK: br i1 icmp ne (void ()* @_ZTH1b, void ()* null),
+// not null:
+// CHECK: call void @_ZTH1b()
+// CHECK: br label
+// finally:
+// CHECK: ret i32* @b
+
+// CHECK: define {{.*}} @[[D_INIT:.*]]()
+// CHECK: call i32 @_Z1gv()
+// CHECK-NEXT: store i32 %{{.*}}, i32* @_ZL1d, align 4
+
+// CHECK: define {{.*}} @[[U_M_INIT:.*]]()
+// CHECK: call i32 @_Z1fv()
+// CHECK-NEXT: store i32 %{{.*}}, i32* @_ZN1U1mE, align 4
+
+// CHECK: define {{.*}} @[[E_INIT:.*]]()
+// CHECK: call i32* @_ZTWN1VIiE1mE()
+// CHECK-NEXT: load i32* %{{.*}}, align 4
+// CHECK-NEXT: store i32 %{{.*}}, i32* @e, align 4
+
+// CHECK: define weak_odr hidden i32* @_ZTWN1VIiE1mE()
+// CHECK: call void @_ZTHN1VIiE1mE()
+// CHECK: ret i32* @_ZN1VIiE1mE
+
+
 struct S { S(); ~S(); };
 struct T { ~T(); };
 
@@ -54,3 +125,49 @@ void tls_dtor() {
   // CHECK: store i8 1, i8* @_ZGVZ8tls_dtorvE1u
   static thread_local const S &u = S();
 }
+
+// CHECK: declare i32 @__cxa_thread_atexit(void (i8*)*, i8*, i8*)
+
+// CHECK: define {{.*}} @[[V_M_INIT:.*]]()
+// CHECK: load i8* bitcast (i64* @_ZGVN1VIiE1mE to i8*)
+// CHECK: %[[V_M_INITIALIZED:.*]] = icmp eq i8 %{{.*}}, 0
+// CHECK: br i1 %[[V_M_INITIALIZED]],
+// need init:
+// CHECK: call i32 @_Z1gv()
+// CHECK: store i32 %{{.*}}, i32* @_ZN1VIiE1mE, align 4
+// CHECK: store i64 1, i64* @_ZGVN1VIiE1mE
+// CHECK: br label
+
+// CHECK: define {{.*}}@[[GLOBAL_INIT:.*]]()
+// CHECK: call void @[[C_INIT]]()
+// CHECK: call void @[[E_INIT]]()
+
+
+// CHECK: define {{.*}}@__tls_init()
+// CHECK: load i8* @__tls_guard
+// CHECK: %[[NEED_TLS_INIT:.*]] = icmp eq i8 %{{.*}}, 0
+// CHECK: store i8 1, i8* @__tls_guard
+// CHECK: br i1 %[[NEED_TLS_INIT]],
+// init:
+// CHECK: call void @[[A_INIT]]()
+// CHECK: call void @[[D_INIT]]()
+// CHECK: call void @[[U_M_INIT]]()
+// CHECK: call void @[[V_M_INIT]]()
+
+
+// CHECK: define weak_odr hidden i32* @_ZTW1a() {
+// CHECK:   call void @_ZTH1a()
+// CHECK:   ret i32* @a
+// CHECK: }
+
+
+// CHECK: declare extern_weak void @_ZTH1b()
+
+
+// CHECK: define internal hidden i32* @_ZTWL1d()
+// CHECK: call void @_ZTHL1d()
+// CHECK: ret i32* @_ZL1d
+
+// CHECK: define weak_odr hidden i32* @_ZTWN1U1mE()
+// CHECK: call void @_ZTHN1U1mE()
+// CHECK: ret i32* @_ZN1U1mE





More information about the cfe-commits mailing list