From: John McCall Date: Sat, 6 Nov 2010 09:44:32 +0000 (+0000) Subject: Simplify the logic for emitting guard variables for template static X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3030eb82593097502469a8b3fc26112c79c75605;p=clang Simplify the logic for emitting guard variables for template static 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 --- 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()) { unsigned int order = D->getAttr()->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(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 > &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 struct A { + static int x; + }; + + template int A::x = foo(); + template struct A; + } + + // 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 struct A { + static int x; + }; + + template int A::x = foo(); + template struct A; + + // 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 }