From 563f0e852c5002ff177aa73802b543d5e3781388 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 23 May 2014 21:13:45 +0000 Subject: [PATCH] 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 llvm-svn: 209555 --- clang/lib/CodeGen/CGDeclCXX.cpp | 13 ++++---- clang/lib/CodeGen/CodeGenModule.cpp | 22 +++++++------ clang/lib/CodeGen/CodeGenModule.h | 18 +++++++++-- clang/lib/CodeGen/MicrosoftCXXABI.cpp | 15 ++++++--- clang/test/CodeGenCXX/apple-kext.cpp | 4 +-- clang/test/CodeGenCXX/init-priority-attr.cpp | 5 ++- .../microsoft-abi-static-initializers.cpp | 36 ++++++++++++---------- ...tic-member-variable-explicit-specialization.cpp | 16 +++++----- 8 files changed, 78 insertions(+), 51 deletions(-) diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index 742be0b..c287740 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -294,10 +294,12 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, // 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::iterator I = @@ -430,8 +432,7 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, // 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); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 0d781fd..9e8401d 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -511,16 +511,17 @@ llvm::GlobalValue *CodeGenModule::GetGlobalValue(StringRef Name) { /// 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 CtorList &Fns, const char *GlobalName) { 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 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)); } diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index eff51ce..9e58351 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -233,7 +233,18 @@ class CodeGenModule : public CodeGenTypeCache { CodeGenModule(const CodeGenModule &) LLVM_DELETED_FUNCTION; void operator=(const CodeGenModule &) LLVM_DELETED_FUNCTION; - typedef std::vector > 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 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 diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 5b7ea61..4887a65 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -1349,6 +1349,15 @@ llvm::Value* MicrosoftCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, 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(CodeGenFunction &CGF, const VarDecl &D, 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(D.getDeclContext())) { - GI = &GuardVariableMap[D.getDeclContext()]; - } + GuardInfo *GI = &GuardVariableMap[D.getDeclContext()]; unsigned BitIndex; if (D.isStaticLocal() && D.isExternallyVisible()) { diff --git a/clang/test/CodeGenCXX/apple-kext.cpp b/clang/test/CodeGenCXX/apple-kext.cpp index 03506a8..0d7ccfb 100644 --- a/clang/test/CodeGenCXX/apple-kext.cpp +++ b/clang/test/CodeGenCXX/apple-kext.cpp @@ -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 { diff --git a/clang/test/CodeGenCXX/init-priority-attr.cpp b/clang/test/CodeGenCXX/init-priority-attr.cpp index 799a6ba..ff155d0 100644 --- a/clang/test/CodeGenCXX/init-priority-attr.cpp +++ b/clang/test/CodeGenCXX/init-priority-attr.cpp @@ -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) diff --git a/clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp b/clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp index ebe456a..782b9dc 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp @@ -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@H@@2VA@@A@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@H@@2VA@@A@YAXXZ", +// CHECK: i8* bitcast (%class.A* @"\01?foo@?$B@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@XZ" +// CHECK: define internal void @"\01??__Es@@YAXXZ"() +// CHECK: call x86_thiscallcc %struct.S* @"\01??0S@@QAE@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@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@5" +// CHECK: define linkonce_odr void @"\01??__Eselectany1@@YAXXZ"() +// CHECK-NOT: @"\01??_Bselectany1 +// CHECK: call x86_thiscallcc %struct.S* @"\01??0S@@QAE@XZ" // CHECK: ret void -// CHECK: define internal void @"\01??__Eselectany2@@YAXXZ"() [[NUW:#[0-9]+]] -// CHECK: load i32* @"\01??_Bselectany2@@3US@@A@5" +// CHECK: define linkonce_odr void @"\01??__Eselectany2@@YAXXZ"() +// CHECK-NOT: @"\01??_Bselectany2 +// CHECK: call x86_thiscallcc %struct.S* @"\01??0S@@QAE@XZ" // CHECK: ret void void StaticLocal() { @@ -96,6 +99,7 @@ class A { public: A() {} ~A() {} + int a; }; template @@ -145,10 +149,10 @@ void force_usage() { (void)B::foo; // (void) - force usage } -// CHECK: define internal void @"\01??__Efoo@?$B@H@@2VA@@A@YAXXZ"() [[NUW]] -// CHECK: load i32* @"\01??_Bfoo@?$B@H@@2VA@@A@5" -// CHECK: store i32 {{.*}}, i32* @"\01??_Bfoo@?$B@H@@2VA@@A@5" -// CHECK: %{{[.0-9A-Z_a-z]+}} = call x86_thiscallcc %class.A* @"\01??0A@@QAE@XZ" +// CHECK: define linkonce_odr void @"\01??__Efoo@?$B@H@@2VA@@A@YAXXZ"() +// CHECK-NOT: and +// CHECK-NOT: ?_Bfoo@ +// CHECK: call x86_thiscallcc %class.A* @"\01??0A@@QAE@XZ" // CHECK: call i32 @atexit(void ()* @"\01??__Ffoo@?$B@H@@2VA@@A@YAXXZ") // CHECK: ret void @@ -160,8 +164,6 @@ void force_usage() { // CHECK: call x86_thiscallcc void @"\01??1A@@QAE@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 } diff --git a/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp b/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp index 4ba8a37..98c09b8 100644 --- a/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp +++ b/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp @@ -12,14 +12,14 @@ template<> int A::a; // CHECK: @_ZN1AIbE1aE = global i32 10 template<> int A::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::a; // Unordered int b = foo(); -- 2.7.4