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");
}
/*************************** 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);
};
// be constant.
GV->setConstant(false);
- EmitCXXStaticLocalInit(D, GV);
+ EmitCXXGuardedInit(D, GV);
}
return GV;
}
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 *
}
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);
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();
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();
}
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.
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);
T = D->getType();
if (getLangOptions().CPlusPlus) {
- EmitCXXGlobalVarDeclInitFunc(D);
Init = EmitNullConstant(T);
NonConstInit = true;
} else {
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());
/// 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);
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 {
/// 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
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());
-// 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
}