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