forked from OSchip/llvm-project
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. llvm-svn: 118336
This commit is contained in:
parent
8b0a71fc31
commit
cdf7ef5437
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -196,7 +196,7 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
|
|||
// be constant.
|
||||
GV->setConstant(false);
|
||||
|
||||
EmitCXXStaticLocalInit(D, GV);
|
||||
EmitCXXGuardedInit(D, GV);
|
||||
}
|
||||
return GV;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue