r209555 - Use comdats to avoid double initialization of weak data
Reid Kleckner
reid at kleckner.net
Fri May 23 14:13:45 PDT 2014
Author: rnk
Date: Fri May 23 16:13:45 2014
New Revision: 209555
URL: http://llvm.org/viewvc/llvm-project?rev=209555&view=rev
Log:
Use comdats to avoid double initialization of weak data
Initializers of global data that can appear multiple TUs (static data
members of class templates or __declspec(selectany) data) are now in a
comdat group keyed on the global variable being initialized. On
non-Windows platforms, this is a code size and startup time
optimization. On Windows, this is necessary for ABI compatibility with
MSVC.
Fixes PR16959.
Reviewers: rsmith
Differential Revision: http://reviews.llvm.org/D3811
Modified:
cfe/trunk/lib/CodeGen/CGDeclCXX.cpp
cfe/trunk/lib/CodeGen/CodeGenModule.cpp
cfe/trunk/lib/CodeGen/CodeGenModule.h
cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
cfe/trunk/test/CodeGenCXX/apple-kext.cpp
cfe/trunk/test/CodeGenCXX/init-priority-attr.cpp
cfe/trunk/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
cfe/trunk/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp
Modified: cfe/trunk/lib/CodeGen/CGDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDeclCXX.cpp?rev=209555&r1=209554&r2=209555&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDeclCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDeclCXX.cpp Fri May 23 16:13:45 2014
@@ -294,10 +294,12 @@ CodeGenModule::EmitCXXGlobalVarDeclInitF
// have unordered initialization.
//
// As a consequence, we can put them into their own llvm.global_ctors entry.
- // This should allow GlobalOpt to fire more often, and allow us to implement
- // the Microsoft C++ ABI, which uses COMDAT elimination to avoid double
- // initializaiton.
- AddGlobalCtor(Fn);
+ //
+ // In addition, put the initializer into a COMDAT group with the global
+ // being initialized. On most platforms, this is a minor startup time
+ // optimization. In the MS C++ ABI, there are no guard variables, so this
+ // COMDAT key is required for correctness.
+ AddGlobalCtor(Fn, 65535, Addr);
DelayedCXXInitPosition.erase(D);
} else {
llvm::DenseMap<const Decl *, unsigned>::iterator I =
@@ -430,8 +432,7 @@ void CodeGenFunction::GenerateCXXGlobalV
// Use guarded initialization if the global variable is weak. This
// occurs for, e.g., instantiated static data members and
// definitions explicitly marked weak.
- if (llvm::GlobalVariable::isWeakLinkage(Addr->getLinkage()) ||
- llvm::GlobalVariable::isLinkOnceLinkage(Addr->getLinkage())) {
+ if (Addr->hasWeakLinkage() || Addr->hasLinkOnceLinkage()) {
EmitCXXGuardedInit(*D, Addr, PerformInit);
} else {
EmitCXXGlobalVarDeclInit(*D, Addr, PerformInit);
Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=209555&r1=209554&r2=209555&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Fri May 23 16:13:45 2014
@@ -511,16 +511,17 @@ llvm::GlobalValue *CodeGenModule::GetGlo
/// AddGlobalCtor - Add a function to the list that will be called before
/// main() runs.
-void CodeGenModule::AddGlobalCtor(llvm::Function * Ctor, int Priority) {
+void CodeGenModule::AddGlobalCtor(llvm::Function *Ctor, int Priority,
+ llvm::Constant *AssociatedData) {
// FIXME: Type coercion of void()* types.
- GlobalCtors.push_back(std::make_pair(Ctor, Priority));
+ GlobalCtors.push_back(Structor(Priority, Ctor, AssociatedData));
}
/// AddGlobalDtor - Add a function to the list that will be called
/// when the module is unloaded.
-void CodeGenModule::AddGlobalDtor(llvm::Function * Dtor, int Priority) {
+void CodeGenModule::AddGlobalDtor(llvm::Function *Dtor, int Priority) {
// FIXME: Type coercion of void()* types.
- GlobalDtors.push_back(std::make_pair(Dtor, Priority));
+ GlobalDtors.push_back(Structor(Priority, Dtor, 0));
}
void CodeGenModule::EmitCtorList(const CtorList &Fns, const char *GlobalName) {
@@ -528,16 +529,19 @@ void CodeGenModule::EmitCtorList(const C
llvm::FunctionType* CtorFTy = llvm::FunctionType::get(VoidTy, false);
llvm::Type *CtorPFTy = llvm::PointerType::getUnqual(CtorFTy);
- // Get the type of a ctor entry, { i32, void ()* }.
- llvm::StructType *CtorStructTy =
- llvm::StructType::get(Int32Ty, llvm::PointerType::getUnqual(CtorFTy), NULL);
+ // Get the type of a ctor entry, { i32, void ()*, i8* }.
+ llvm::StructType *CtorStructTy = llvm::StructType::get(
+ Int32Ty, llvm::PointerType::getUnqual(CtorFTy), VoidPtrTy, NULL);
// Construct the constructor and destructor arrays.
SmallVector<llvm::Constant*, 8> Ctors;
for (CtorList::const_iterator I = Fns.begin(), E = Fns.end(); I != E; ++I) {
llvm::Constant *S[] = {
- llvm::ConstantInt::get(Int32Ty, I->second, false),
- llvm::ConstantExpr::getBitCast(I->first, CtorPFTy)
+ llvm::ConstantInt::get(Int32Ty, I->Priority, false),
+ llvm::ConstantExpr::getBitCast(I->Initializer, CtorPFTy),
+ (I->AssociatedData
+ ? llvm::ConstantExpr::getBitCast(I->AssociatedData, VoidPtrTy)
+ : llvm::Constant::getNullValue(VoidPtrTy))
};
Ctors.push_back(llvm::ConstantStruct::get(CtorStructTy, S));
}
Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=209555&r1=209554&r2=209555&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.h Fri May 23 16:13:45 2014
@@ -233,7 +233,18 @@ class CodeGenModule : public CodeGenType
CodeGenModule(const CodeGenModule &) LLVM_DELETED_FUNCTION;
void operator=(const CodeGenModule &) LLVM_DELETED_FUNCTION;
- typedef std::vector<std::pair<llvm::Constant*, int> > CtorList;
+ struct Structor {
+ Structor() : Priority(0), Initializer(nullptr), AssociatedData(nullptr) {}
+ Structor(int Priority, llvm::Constant *Initializer,
+ llvm::Constant *AssociatedData)
+ : Priority(Priority), Initializer(Initializer),
+ AssociatedData(AssociatedData) {}
+ int Priority;
+ llvm::Constant *Initializer;
+ llvm::Constant *AssociatedData;
+ };
+
+ typedef std::vector<Structor> CtorList;
ASTContext &Context;
const LangOptions &LangOpts;
@@ -1081,8 +1092,9 @@ private:
bool PerformInit);
// FIXME: Hardcoding priority here is gross.
- void AddGlobalCtor(llvm::Function *Ctor, int Priority=65535);
- void AddGlobalDtor(llvm::Function *Dtor, int Priority=65535);
+ void AddGlobalCtor(llvm::Function *Ctor, int Priority = 65535,
+ llvm::Constant *AssociatedData = 0);
+ void AddGlobalDtor(llvm::Function *Dtor, int Priority = 65535);
/// Generates a global array of functions and priorities using the given list
/// and name. This array will have appending linkage and is suitable for use
Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=209555&r1=209554&r2=209555&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Fri May 23 16:13:45 2014
@@ -1349,6 +1349,15 @@ llvm::Value* MicrosoftCXXABI::Initialize
void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
llvm::GlobalVariable *GV,
bool PerformInit) {
+ // MSVC only uses guards for static locals.
+ if (!D.isStaticLocal()) {
+ assert(GV->hasWeakLinkage() || GV->hasLinkOnceLinkage());
+ // GlobalOpt is allowed to discard the initializer, so use linkonce_odr.
+ CGF.CurFn->setLinkage(llvm::GlobalValue::LinkOnceODRLinkage);
+ CGF.EmitCXXGlobalVarDeclInit(D, GV, PerformInit);
+ return;
+ }
+
// MSVC always uses an i32 bitfield to guard initialization, which is *not*
// threadsafe. Since the user may be linking in inline functions compiled by
// cl.exe, there's no reason to provide a false sense of security by using
@@ -1362,11 +1371,7 @@ void MicrosoftCXXABI::EmitGuardedInit(Co
llvm::ConstantInt *Zero = llvm::ConstantInt::get(GuardTy, 0);
// Get the guard variable for this function if we have one already.
- GuardInfo EmptyGuardInfo;
- GuardInfo *GI = &EmptyGuardInfo;
- if (isa<FunctionDecl>(D.getDeclContext())) {
- GI = &GuardVariableMap[D.getDeclContext()];
- }
+ GuardInfo *GI = &GuardVariableMap[D.getDeclContext()];
unsigned BitIndex;
if (D.isStaticLocal() && D.isExternallyVisible()) {
Modified: cfe/trunk/test/CodeGenCXX/apple-kext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/apple-kext.cpp?rev=209555&r1=209554&r2=209555&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/apple-kext.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/apple-kext.cpp Fri May 23 16:13:45 2014
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fno-use-cxa-atexit -fapple-kext -emit-llvm -o - %s | FileCheck %s
// CHECK: @_ZN5test01aE = global [[A:%.*]] zeroinitializer
-// CHECK: @llvm.global_ctors = appending global {{.*}} { i32 65535, void ()* [[CTOR0:@.*]] }
-// CHECK: @llvm.global_dtors = appending global {{.*}} { i32 65535, void ()* [[DTOR0:@.*]] }
+// CHECK: @llvm.global_ctors = appending global {{.*}} { i32 65535, void ()* [[CTOR0:@.*]], i8* null }
+// CHECK: @llvm.global_dtors = appending global {{.*}} { i32 65535, void ()* [[DTOR0:@.*]], i8* null }
// rdar://11241230
namespace test0 {
Modified: cfe/trunk/test/CodeGenCXX/init-priority-attr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/init-priority-attr.cpp?rev=209555&r1=209554&r2=209555&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/init-priority-attr.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/init-priority-attr.cpp Fri May 23 16:13:45 2014
@@ -27,7 +27,10 @@ public:
A C::a = A();
-// CHECK: @llvm.global_ctors = appending global [3 x { i32, void ()* }] [{ i32, void ()* } { i32 200, void ()* @_GLOBAL__I_000200 }, { i32, void ()* } { i32 300, void ()* @_GLOBAL__I_000300 }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__sub_I_init_priority_attr.cpp }]
+// CHECK: @llvm.global_ctors = appending global [3 x { i32, void ()*, i8* }]
+// CHECK: [{ i32, void ()*, i8* } { i32 200, void ()* @_GLOBAL__I_000200, i8* null },
+// CHECK: { i32, void ()*, i8* } { i32 300, void ()* @_GLOBAL__I_000300, i8* null },
+// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_init_priority_attr.cpp, i8* null }]
// CHECK: _GLOBAL__I_000200()
// CHECK: _Z3fooi(i32 3)
Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-static-initializers.cpp?rev=209555&r1=209554&r2=209555&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-static-initializers.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-static-initializers.cpp Fri May 23 16:13:45 2014
@@ -1,8 +1,9 @@
// RUN: %clang_cc1 -fms-extensions -emit-llvm %s -o - -mconstructor-aliases -triple=i386-pc-win32 | FileCheck %s
-// CHECK: @llvm.global_ctors = appending global [2 x { i32, void ()* }]
-// CHECK: [{ i32, void ()* } { i32 65535, void ()* @"\01??__Efoo@?$B at H@@2VA@@A at YAXXZ"
-// CHECK: { i32, void ()* } { i32 65535, void ()* @_GLOBAL__sub_I_microsoft_abi_static_initializers.cpp }]
+// CHECK: @llvm.global_ctors = appending global [2 x { i32, void ()*, i8* }]
+// CHECK: [{ i32, void ()*, i8* } { i32 65535, void ()* @"\01??__Efoo@?$B at H@@2VA@@A at YAXXZ",
+// CHECK: i8* bitcast (%class.A* @"\01?foo@?$B at H@@2VA@@A" to i8*) },
+// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_microsoft_abi_static_initializers.cpp, i8* null }]
struct S {
S();
@@ -11,12 +12,12 @@ struct S {
S s;
-// CHECK: define internal void @"\01??__Es@@YAXXZ"() [[NUW:#[0-9]+]]
-// CHECK: %{{[.0-9A-Z_a-z]+}} = call x86_thiscallcc %struct.S* @"\01??0S@@QAE at XZ"
+// CHECK: define internal void @"\01??__Es@@YAXXZ"()
+// CHECK: call x86_thiscallcc %struct.S* @"\01??0S@@QAE at XZ"
// CHECK: call i32 @atexit(void ()* @"\01??__Fs@@YAXXZ")
// CHECK: ret void
-// CHECK: define internal void @"\01??__Fs@@YAXXZ"() [[NUW]] {
+// CHECK: define internal void @"\01??__Fs@@YAXXZ"()
// CHECK: call x86_thiscallcc void @"\01??1S@@QAE at XZ"
// CHECK: ret void
@@ -24,11 +25,13 @@ S s;
// the same global.
__declspec(selectany) S selectany1;
__declspec(selectany) S selectany2;
-// CHECK: define internal void @"\01??__Eselectany1@@YAXXZ"() [[NUW:#[0-9]+]]
-// CHECK: load i32* @"\01??_Bselectany1@@3US@@A at 5"
-// CHECK: ret void
-// CHECK: define internal void @"\01??__Eselectany2@@YAXXZ"() [[NUW:#[0-9]+]]
-// CHECK: load i32* @"\01??_Bselectany2@@3US@@A at 5"
+// CHECK: define linkonce_odr void @"\01??__Eselectany1@@YAXXZ"()
+// CHECK-NOT: @"\01??_Bselectany1
+// CHECK: call x86_thiscallcc %struct.S* @"\01??0S@@QAE at XZ"
+// CHECK: ret void
+// CHECK: define linkonce_odr void @"\01??__Eselectany2@@YAXXZ"()
+// CHECK-NOT: @"\01??_Bselectany2
+// CHECK: call x86_thiscallcc %struct.S* @"\01??0S@@QAE at XZ"
// CHECK: ret void
void StaticLocal() {
@@ -96,6 +99,7 @@ class A {
public:
A() {}
~A() {}
+ int a;
};
template<typename T>
@@ -145,10 +149,10 @@ void force_usage() {
(void)B<int>::foo; // (void) - force usage
}
-// CHECK: define internal void @"\01??__Efoo@?$B at H@@2VA@@A at YAXXZ"() [[NUW]]
-// CHECK: load i32* @"\01??_Bfoo@?$B at H@@2VA@@A at 5"
-// CHECK: store i32 {{.*}}, i32* @"\01??_Bfoo@?$B at H@@2VA@@A at 5"
-// CHECK: %{{[.0-9A-Z_a-z]+}} = call x86_thiscallcc %class.A* @"\01??0A@@QAE at XZ"
+// CHECK: define linkonce_odr void @"\01??__Efoo@?$B at H@@2VA@@A at YAXXZ"()
+// CHECK-NOT: and
+// CHECK-NOT: ?_Bfoo@
+// CHECK: call x86_thiscallcc %class.A* @"\01??0A@@QAE at XZ"
// CHECK: call i32 @atexit(void ()* @"\01??__Ffoo@?$B at H@@2VA@@A at YAXXZ")
// CHECK: ret void
@@ -160,8 +164,6 @@ void force_usage() {
// CHECK: call x86_thiscallcc void @"\01??1A@@QAE at XZ"{{.*}}foo
// CHECK: ret void
-// CHECK: define internal void @_GLOBAL__sub_I_microsoft_abi_static_initializers.cpp() [[NUW]] {
+// CHECK: define internal void @_GLOBAL__sub_I_microsoft_abi_static_initializers.cpp()
// CHECK: call void @"\01??__Es@@YAXXZ"()
// CHECK: ret void
-
-// CHECK: attributes [[NUW]] = { nounwind }
Modified: cfe/trunk/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp?rev=209555&r1=209554&r2=209555&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp Fri May 23 16:13:45 2014
@@ -12,14 +12,14 @@ template<> int A<char>::a;
// CHECK: @_ZN1AIbE1aE = global i32 10
template<> int A<bool>::a = 10;
-// CHECK: @llvm.global_ctors = appending global [7 x { i32, void ()* }]
-// CHECK: [{ i32, void ()* } { i32 65535, void ()* @[[unordered1:[^ ]*]] },
-// CHECK: { i32, void ()* } { i32 65535, void ()* @[[unordered2:[^ ]*]] },
-// CHECK: { i32, void ()* } { i32 65535, void ()* @[[unordered3:[^ ]*]] },
-// CHECK: { i32, void ()* } { i32 65535, void ()* @[[unordered4:[^ ]*]] },
-// CHECK: { i32, void ()* } { i32 65535, void ()* @[[unordered5:[^ ]*]] },
-// CHECK: { i32, void ()* } { i32 65535, void ()* @[[unordered6:[^ ]*]] },
-// CHECK: { i32, void ()* } { i32 65535, void ()* @_GLOBAL__sub_I_static_member_variable_explicit_specialization.cpp }]
+// CHECK: @llvm.global_ctors = appending global [7 x { i32, void ()*, i8* }]
+// CHECK: [{ i32, void ()*, i8* } { i32 65535, void ()* @[[unordered1:[^,]*]], i8* bitcast (i32* @_ZN1AIsE1aE to i8*) },
+// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered2:[^,]*]], i8* bitcast (i16* @_Z1xIsE to i8*) },
+// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered3:[^,]*]], i8* bitcast (i32* @_ZN2ns1aIiE1iE to i8*) },
+// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered4:[^,]*]], i8* bitcast (i32* @_ZN2ns1b1iIiEE to i8*) },
+// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered5:[^,]*]], i8* bitcast (i32* @_ZN1AIvE1aE to i8*) },
+// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered6:[^,]*]], i8* @_Z1xIcE },
+// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_static_member_variable_explicit_specialization.cpp, i8* null }]
template int A<short>::a; // Unordered
int b = foo();
More information about the cfe-commits
mailing list