Skip to content

Commit b969e84

Browse files
committed
Add a separate llvm.global_ctors entry for linkonce_odr data initializers
Summary: These typically come from static data members of class template specializations. This accomplishes two things: 1. May expose GlobalOpt optimizations for Itanium C++ ABI code. 2. Works toward fixing double initialization in the Microsoft C++ ABI. CC: cfe-commits Differential Revision: http://llvm-reviews.chandlerc.com/D1475 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@189051 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 0bd62ad commit b969e84

File tree

3 files changed

+43
-2
lines changed

3 files changed

+43
-2
lines changed

lib/CodeGen/CGDeclCXX.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,19 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
278278
OrderGlobalInits Key(order, PrioritizedCXXGlobalInits.size());
279279
PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn));
280280
DelayedCXXInitPosition.erase(D);
281+
} else if (D->getInstantiatedFromStaticDataMember()) {
282+
// C++ [basic.start.init]p2:
283+
// Defnitions of explicitly specialized class template static data members
284+
// have ordered initialization. Other class template static data members
285+
// (i.e., implicitly or explicitly instantiated specializations) have
286+
// unordered initialization.
287+
//
288+
// As a consequence, we can put them into their own llvm.global_ctors entry.
289+
// This should allow GlobalOpt to fire more often, and allow us to implement
290+
// the Microsoft C++ ABI, which uses COMDAT elimination to avoid double
291+
// initializaiton.
292+
AddGlobalCtor(Fn);
293+
DelayedCXXInitPosition.erase(D);
281294
} else {
282295
llvm::DenseMap<const Decl *, unsigned>::iterator I =
283296
DelayedCXXInitPosition.find(D);

test/CodeGenCXX/microsoft-abi-static-initializers.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
22

3+
// CHECK: @llvm.global_ctors = appending global [2 x { i32, void ()* }]
4+
// CHECK: [{ i32, void ()* } { i32 65535, void ()* [[INIT_foo:@.*global_var.*]] },
5+
// CHECK: { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_a }]
6+
37
struct S {
48
S() {}
59
~S() {}
@@ -33,7 +37,7 @@ void force_usage() {
3337
(void)B<int>::foo; // (void) - force usage
3438
}
3539

36-
// CHECK: define internal void [[INIT_foo:@.*global_var.*]] [[NUW]]
40+
// CHECK: define internal void [[INIT_foo]]() [[NUW]]
3741
// CHECK: %{{[.0-9A-Z_a-z]+}} = call x86_thiscallcc %class.A* @"\01??0A@@QAE@XZ"
3842
// CHECK: call i32 @atexit(void ()* [[FOO_DTOR:@"__dtor_.*foo@.*]])
3943
// CHECK: ret void
@@ -48,7 +52,6 @@ void force_usage() {
4852

4953
// CHECK: define internal void @_GLOBAL__I_a() [[NUW]] {
5054
// CHECK: call void [[INIT_s]]
51-
// CHECK: call void [[INIT_foo]]
5255
// CHECK: ret void
5356

5457
// CHECK: attributes [[NUW]] = { nounwind }

test/CodeGenCXX/static-member-variable-explicit-specialization.cpp

+25
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
22
// CHECK: ; ModuleID
3+
34
template<typename> struct A { static int a; };
45

56
// CHECK-NOT: @_ZN1AIcE1aE
@@ -8,4 +9,28 @@ template<> int A<char>::a;
89
// CHECK: @_ZN1AIbE1aE = global i32 10
910
template<> int A<bool>::a = 10;
1011

12+
// CHECK: @llvm.global_ctors = appending global [2 x { i32, void ()* }]
13+
// CHECK: [{ i32, void ()* } { i32 65535, void ()* @__cxx_global_var_init },
14+
// CHECK: { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_a }]
15+
16+
extern "C" int foo();
17+
template<> int A<short>::a = foo(); // Separate global_ctor entry
18+
int b = foo(); // Goes in _GLOBAL__I_a
19+
int c = foo(); // Goes in _GLOBAL__I_a
20+
21+
// An explicit specialization is ordered, and goes in __GLOBAL_I_a.
22+
template<> struct A<int> { static int a; };
23+
int A<int>::a = foo();
24+
25+
// CHECK: define internal void @__cxx_global_var_init()
26+
// CHECK: call i32 @foo()
27+
// CHECK: store {{.*}} @_ZN1AIsE1aE
28+
// CHECK: ret
1129

30+
// CHECK: define internal void @_GLOBAL__I_a()
31+
// We call unique stubs for every ordered dynamic initializer in the TU.
32+
// CHECK: call
33+
// CHECK: call
34+
// CHECK: call
35+
// CHECK-NOT: call
36+
// CHECK: ret

0 commit comments

Comments
 (0)