]> granicus.if.org Git - clang/commitdiff
Simplify the logic for emitting guard variables for template static
authorJohn McCall <rjmccall@apple.com>
Sat, 6 Nov 2010 09:44:32 +0000 (09:44 +0000)
committerJohn McCall <rjmccall@apple.com>
Sat, 6 Nov 2010 09:44:32 +0000 (09:44 +0000)
data members by delaying the emission of the initializer until after
linkage and visibility have been set on the global.  Also, don't
emit a guard unless the variable actually ends up with vague linkage,
and don't use thread-safe statics in any case.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@118336 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGCXX.cpp
lib/CodeGen/CGCXXABI.h
lib/CodeGen/CGDecl.cpp
lib/CodeGen/CGDeclCXX.cpp
lib/CodeGen/CodeGenFunction.h
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h
lib/CodeGen/ItaniumCXXABI.cpp
test/CodeGenCXX/static-data-member.cpp

index 98ccc76fbf31990dfdb3786a730929fb1ec1b235..ce1ae32398ef28c9a60c1b3bd66b11a8d2876ee9 100644 (file)
@@ -468,8 +468,8 @@ void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr,
   CookieSize = CharUnits::Zero();
 }
 
-void CGCXXABI::EmitStaticLocalInit(CodeGenFunction &CGF,
-                                   const VarDecl &D,
-                                   llvm::GlobalVariable *GV) {
+void CGCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
+                               const VarDecl &D,
+                               llvm::GlobalVariable *GV) {
   ErrorUnsupportedABI(CGF, "static local variable initialization");
 }
index b99216b786b3170bee0bb2b6fc05d997bf9538be..0fca02dac0c99d70251c5e7233735f1da7c65c59 100644 (file)
@@ -221,11 +221,14 @@ public:
 
   /*************************** Static local guards ****************************/
 
-  /// Emits the initializer and destructor setup for the given static
-  /// local variable, given that it's reachable and couldn't be
-  /// emitted as a constant.
-  virtual void EmitStaticLocalInit(CodeGenFunction &CGF, const VarDecl &D,
-                                   llvm::GlobalVariable *DeclPtr);
+  /// Emits the guarded initializer and destructor setup for the given
+  /// variable, given that it couldn't be emitted as a constant.
+  ///
+  /// The variable may be:
+  ///   - a static local variable
+  ///   - a static data member of a class template instantiation
+  virtual void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
+                               llvm::GlobalVariable *DeclPtr);
 
 };
 
index 5ac8508375fb87cfb804c2969641edfe3c57d410..02da0a533b8e897fa2fd808e084007c5b4630e29 100644 (file)
@@ -196,7 +196,7 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
       // be constant.
       GV->setConstant(false);
 
-      EmitCXXStaticLocalInit(D, GV);
+      EmitCXXGuardedInit(D, GV);
     }
     return GV;
   }
index 6567ffb07d88c8b199448413d0a466c80b9f2a95..17571fccf08546001c009425e63c7269e57fd422 100644 (file)
@@ -140,9 +140,9 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
   Builder.CreateCall(AtExitFn, &Args[0], llvm::array_endof(Args));
 }
 
-void CodeGenFunction::EmitCXXStaticLocalInit(const VarDecl &D,
-                                             llvm::GlobalVariable *DeclPtr) {
-  CGM.getCXXABI().EmitStaticLocalInit(*this, D, DeclPtr);
+void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
+                                         llvm::GlobalVariable *DeclPtr) {
+  CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr);
 }
 
 static llvm::Function *
@@ -165,7 +165,8 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
 }
 
 void
-CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D) {
+CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
+                                            llvm::GlobalVariable *Addr) {
   const llvm::FunctionType *FTy
     = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
                               false);
@@ -174,7 +175,7 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D) {
   llvm::Function *Fn =
     CreateGlobalInitOrDestructFunction(*this, FTy, "__cxx_global_var_init");
 
-  CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D);
+  CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr);
 
   if (D->hasAttr<InitPriorityAttr>()) {
     unsigned int order = D->getAttr<InitPriorityAttr>()->getPriority();
@@ -247,26 +248,20 @@ void CodeGenModule::EmitCXXGlobalDtorFunc() {
   AddGlobalDtor(Fn);
 }
 
+/// Emit the code necessary to initialize the given global variable.
 void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
-                                                       const VarDecl *D) {
+                                                       const VarDecl *D,
+                                                 llvm::GlobalVariable *Addr) {
   StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
                 SourceLocation());
 
-  llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D);
-  if (D->isStaticDataMember() &&
-      D->getInstantiatedFromStaticDataMember() && D->getInit()){
-    llvm::GlobalVariable *GV = dyn_cast<llvm::GlobalVariable>(DeclPtr);
-    assert(GV && "GenerateCXXGlobalVarDeclInitFunc - GV is null");
-    llvm::GlobalValue::LinkageTypes Linkage = 
-      CGM.GetLLVMLinkageVarDefinition(D, GV);
-    if (Linkage == llvm::GlobalVariable::WeakAnyLinkage) {
-      GV->setConstant(false);
-      EmitCXXStaticLocalInit(*D, GV);
-      FinishFunction();
-      return;
-    }
+  // Use guarded initialization if the global variable is weak due to
+  // being a class template's static data member.
+  if (Addr->hasWeakLinkage() && D->getInstantiatedFromStaticDataMember()) {
+    EmitCXXGuardedInit(*D, Addr);
+  } else {
+    EmitCXXGlobalVarDeclInit(*D, Addr);
   }
-  EmitCXXGlobalVarDeclInit(*D, DeclPtr);
 
   FinishFunction();
 }
index 09b7168a9ea546b6a2829475def56bbe0c530e55..1898c0871982ce1d279b23af2cd9c8f0dab54f7e 100644 (file)
@@ -1628,7 +1628,12 @@ public:
   void EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
                                      llvm::Constant *DeclPtr);
 
-  void EmitCXXStaticLocalInit(const VarDecl &D, llvm::GlobalVariable *DeclPtr);
+  /// Emit code in this function to perform a guarded variable
+  /// initialization.  Guarded initializations are used when it's not
+  /// possible to prove that an initialization will be done exactly
+  /// once, e.g. with a static local variable or a static data member
+  /// of a class template.
+  void EmitCXXGuardedInit(const VarDecl &D, llvm::GlobalVariable *DeclPtr);
 
   /// GenerateCXXGlobalInitFunc - Generates code for initializing global
   /// variables.
@@ -1642,7 +1647,8 @@ public:
                                  const std::vector<std::pair<llvm::WeakVH,
                                    llvm::Constant*> > &DtorsAndObjects);
 
-  void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D);
+  void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D,
+                                        llvm::GlobalVariable *Addr);
 
   void EmitCXXConstructExpr(const CXXConstructExpr *E, AggValueSlot Dest);
 
index a2b80bea6c0754e134e0db99fdb012de20dae9b0..a3cf69b675cd27320a4ffa4b58c1403f3c51011e 100644 (file)
@@ -1102,7 +1102,6 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
         T = D->getType();
       
       if (getLangOptions().CPlusPlus) {
-        EmitCXXGlobalVarDeclInitFunc(D);
         Init = EmitNullConstant(T);
         NonConstInit = true;
       } else {
@@ -1184,6 +1183,10 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
 
   SetCommonAttributes(D, GV);
 
+  // Emit the initializer function if necessary.
+  if (NonConstInit)
+    EmitCXXGlobalVarDeclInitFunc(D, GV);
+
   // Emit global variable debug information.
   if (CGDebugInfo *DI = getDebugInfo()) {
     DI->setLocation(D->getLocation());
index 681ab0a008daa803d617ef0043c9ecb9bd6a06b6..3a5677b303bd124e75180510bc592ffc29105ab1 100644 (file)
@@ -590,7 +590,8 @@ private:
   /// EmitCXXGlobalDtorFunc - Emit the function that destroys C++ globals.
   void EmitCXXGlobalDtorFunc();
 
-  void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D);
+  void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
+                                    llvm::GlobalVariable *Addr);
 
   // FIXME: Hardcoding priority here is gross.
   void AddGlobalCtor(llvm::Function *Ctor, int Priority=65535);
index 94c1f60a8b28fa7bef3ed6f0da2222cebb0da33c..839e0476d4054104d09502f0579c150b4ad40f8c 100644 (file)
@@ -120,8 +120,8 @@ public:
                        QualType ElementType, llvm::Value *&NumElements,
                        llvm::Value *&AllocPtr, CharUnits &CookieSize);
 
-  void EmitStaticLocalInit(CodeGenFunction &CGF, const VarDecl &D,
-                           llvm::GlobalVariable *DeclPtr);
+  void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
+                       llvm::GlobalVariable *DeclPtr);
 };
 
 class ARMCXXABI : public ItaniumCXXABI {
@@ -1078,11 +1078,15 @@ namespace {
 
 /// The ARM code here follows the Itanium code closely enough that we
 /// just special-case it at particular places.
-void ItaniumCXXABI::EmitStaticLocalInit(CodeGenFunction &CGF,
-                                        const VarDecl &D,
-                                        llvm::GlobalVariable *GV) {
+void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
+                                    const VarDecl &D,
+                                    llvm::GlobalVariable *GV) {
   CGBuilderTy &Builder = CGF.Builder;
-  bool ThreadsafeStatics = getContext().getLangOptions().ThreadsafeStatics;
+
+  // We only need to use thread-safe statics for local variables;
+  // global initialization is always single-threaded.
+  bool ThreadsafeStatics = (getContext().getLangOptions().ThreadsafeStatics &&
+                            D.isLocalVarDecl());
   
   // Guard variables are 64 bits in the generic ABI and 32 bits on ARM.
   const llvm::IntegerType *GuardTy
@@ -1093,16 +1097,10 @@ void ItaniumCXXABI::EmitStaticLocalInit(CodeGenFunction &CGF,
   llvm::SmallString<256> GuardVName;
   getMangleContext().mangleItaniumGuardVariable(&D, GuardVName);
 
-  // FIXME: we should just absorb linkage and visibility from the
-  // variable, but that's not always set up properly just yet.
-  llvm::GlobalValue::LinkageTypes Linkage = GV->getLinkage();
-  if (D.isStaticDataMember() &&
-      D.getInstantiatedFromStaticDataMember())
-    Linkage = llvm::GlobalVariable::WeakAnyLinkage;
-  
+  // Just absorb linkage and visibility from the variable.
   llvm::GlobalVariable *GuardVariable =
     new llvm::GlobalVariable(CGM.getModule(), GuardTy,
-                             false, Linkage,
+                             false, GV->getLinkage(),
                              llvm::ConstantInt::get(GuardTy, 0),
                              GuardVName.str());
   GuardVariable->setVisibility(GV->getVisibility());
index b3a2af2aafe32c847e43f28380244491484bf3ab..64fca2eb6837de7b89764d4ae7749c0211c00836 100644 (file)
@@ -1,18 +1,66 @@
-// RUN: %clang_cc1 -emit-llvm -o - %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
 
-// CHECK: @_ZN1A1aE = constant i32 10
+// CHECK: @_ZN5test11A1aE = constant i32 10, align 4
+// CHECK: @_ZN5test212_GLOBAL__N_11AIiE1xE = internal global i32 0, align 4
+// CHECK: @_ZN5test31AIiE1xE = weak global i32 0, align 4
+// CHECK: @_ZGVN5test31AIiE1xE = weak global i64 0
 
 // PR5564.
-struct A {
-  static const int a = 10;
-};
+namespace test1 {
+  struct A {
+    static const int a = 10;
+  };
 
-const int A::a;
+  const int A::a;
 
-struct S { 
-  static int i;
-};
+  struct S { 
+    static int i;
+  };
 
-void f() { 
-  int a = S::i;
+  void f() { 
+    int a = S::i;
+  }
+}
+
+// Test that we don't use guards for initializing template static data
+// members with internal linkage.
+namespace test2 {
+  int foo();
+
+  namespace {
+    template <class T> struct A {
+      static int x;
+    };
+
+    template <class T> int A<T>::x = foo();
+    template struct A<int>;
+  }
+
+  // CHECK: define internal void @__cxx_global_var_init()
+  // CHECK:      [[TMP:%.*]] = call i32 @_ZN5test23fooEv()
+  // CHECK-NEXT: store i32 [[TMP]], i32* @_ZN5test212_GLOBAL__N_11AIiE1xE, align 4
+  // CHECK-NEXT: ret void
+}
+
+// Test that we don't use threadsafe statics when initializing
+// template static data members.
+namespace test3 {
+  int foo();
+
+  template <class T> struct A {
+    static int x;
+  };
+
+  template <class T> int A<T>::x = foo();
+  template struct A<int>;
+
+  // CHECK: define internal void @__cxx_global_var_init1()
+  // CHECK:      [[GUARDBYTE:%.*]] = load i8* bitcast (i64* @_ZGVN5test31AIiE1xE to i8*)
+  // CHECK-NEXT: [[UNINITIALIZED:%.*]] = icmp eq i8 [[GUARDBYTE]], 0
+  // CHECK-NEXT: br i1 [[UNINITIALIZED]]
+  // CHECK:      [[TMP:%.*]] = call i32 @_ZN5test33fooEv()
+  // CHECK-NEXT: store i32 [[TMP]], i32* @_ZN5test31AIiE1xE, align 4
+  // CHECK-NEXT: store i64 1, i64* @_ZGVN5test31AIiE1xE
+  // CHECK-NEXT: br label
+  // CHECK:      ret void
 }