diff options
-rw-r--r-- | lib/CodeGen/CGCXX.cpp | 6 | ||||
-rw-r--r-- | lib/CodeGen/CGCXXABI.h | 13 | ||||
-rw-r--r-- | lib/CodeGen/CGDecl.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CGDeclCXX.cpp | 35 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 10 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.cpp | 5 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.h | 3 | ||||
-rw-r--r-- | lib/CodeGen/ItaniumCXXABI.cpp | 26 | ||||
-rw-r--r-- | test/CodeGenCXX/static-data-member.cpp | 70 |
9 files changed, 112 insertions, 58 deletions
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 98ccc76fbf..ce1ae32398 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -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"); } diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index b99216b786..0fca02dac0 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -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); }; diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 5ac8508375..02da0a533b 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -196,7 +196,7 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D, // be constant. GV->setConstant(false); - EmitCXXStaticLocalInit(D, GV); + EmitCXXGuardedInit(D, GV); } return GV; } diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 6567ffb07d..17571fccf0 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -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(); } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 09b7168a9e..1898c08719 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -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); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index a2b80bea6c..a3cf69b675 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -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()); diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 681ab0a008..3a5677b303 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -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); diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 94c1f60a8b..839e0476d4 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -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()); diff --git a/test/CodeGenCXX/static-data-member.cpp b/test/CodeGenCXX/static-data-member.cpp index b3a2af2aaf..64fca2eb68 100644 --- a/test/CodeGenCXX/static-data-member.cpp +++ b/test/CodeGenCXX/static-data-member.cpp @@ -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 } |