diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -544,6 +544,8 @@ llvm::GlobalVariable *COMDATKey = supportsCOMDAT() && D->isExternallyVisible() ? Addr : nullptr; + bool IsInstantiation = + isTemplateInstantiation(D->getTemplateSpecializationKind()); if (D->getTLSKind()) { // FIXME: Should we support init_priority for thread_local? @@ -557,7 +559,7 @@ OrderGlobalInitsOrStermFinalizers Key(IPA->getPriority(), PrioritizedCXXGlobalInits.size()); PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn)); - } else if (isTemplateInstantiation(D->getTemplateSpecializationKind()) || + } else if (IsInstantiation || getContext().GetGVALinkageForVariable(D) == GVA_DiscardableODR || D->hasAttr()) { // C++ [basic.start.init]p2: @@ -577,7 +579,7 @@ // COMDAT group associated with the global, so the initializers get folded // too. - AddGlobalCtor(Fn, 65535, COMDATKey); + AddGlobalCtor(Fn, 65535, COMDATKey, IsInstantiation); if (COMDATKey && (getTriple().isOSBinFormatELF() || getTarget().getCXXABI().isMicrosoft())) { // When COMDAT is used on ELF or in the MS C++ ABI, the key must be in diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1544,7 +1544,8 @@ // FIXME: Hardcoding priority here is gross. void AddGlobalCtor(llvm::Function *Ctor, int Priority = 65535, - llvm::Constant *AssociatedData = nullptr); + llvm::Constant *AssociatedData = nullptr, + bool InsertFront = false); void AddGlobalDtor(llvm::Function *Dtor, int Priority = 65535, bool IsDtorAttrFunc = false); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1556,9 +1556,13 @@ /// AddGlobalCtor - Add a function to the list that will be called before /// main() runs. void CodeGenModule::AddGlobalCtor(llvm::Function *Ctor, int Priority, - llvm::Constant *AssociatedData) { + llvm::Constant *AssociatedData, + bool InsertFront) { // FIXME: Type coercion of void()* types. - GlobalCtors.push_back(Structor(Priority, Ctor, AssociatedData)); + if (InsertFront) + GlobalCtors.emplace(GlobalCtors.begin(), Priority, Ctor, AssociatedData); + else + GlobalCtors.emplace_back(Priority, Ctor, AssociatedData); } /// AddGlobalDtor - Add a function to the list that will be called diff --git a/clang/test/CodeGenCXX/aix-static-init-temp-spec-and-inline-var.cpp b/clang/test/CodeGenCXX/aix-static-init-temp-spec-and-inline-var.cpp --- a/clang/test/CodeGenCXX/aix-static-init-temp-spec-and-inline-var.cpp +++ b/clang/test/CodeGenCXX/aix-static-init-temp-spec-and-inline-var.cpp @@ -47,7 +47,7 @@ // CHECK: @_ZGVN5test12t2E = linkonce_odr global i64 0, align 8 // CHECK: @_ZGVN5test21AIvE8instanceE = weak_odr global i64 0, align 8 // CHECK: @_ZGVN5test12t1IiEE = linkonce_odr global i64 0, align 8 -// CHECK: @llvm.global_ctors = appending global [4 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__cxx_global_var_init.1, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @__cxx_global_var_init.2, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @__cxx_global_var_init.4, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I__, i8* null }] +// CHECK: @llvm.global_ctors = appending global [4 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__cxx_global_var_init.4, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @__cxx_global_var_init.2, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @__cxx_global_var_init.1, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I__, i8* null }] // CHECK: @llvm.global_dtors = appending global [4 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__finalize__ZN5test12t2E, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @__finalize__ZN5test21AIvE8instanceE, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @__finalize__ZN5test12t1IiEE, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__D_a, i8* null }] // CHECK: define internal void @__cxx_global_var_init() [[ATTR:#[0-9]+]] { diff --git a/clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp b/clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp --- a/clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp @@ -1,10 +1,10 @@ // RUN: %clang_cc1 -no-opaque-pointers -fms-extensions -fno-threadsafe-statics -emit-llvm %s -o - -mconstructor-aliases -triple=i386-pc-win32 | FileCheck %s // CHECK: @llvm.global_ctors = appending global [5 x { i32, void ()*, i8* }] [ +// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"??__E?foo@?$B@H@@2VA@@A@@YAXXZ", i8* bitcast (%class.A* @"?foo@?$B@H@@2VA@@A" to i8*) }, +// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"??__E?s@?$ExportedTemplate@H@@2US@@A@@YAXXZ", i8* getelementptr inbounds (%struct.S, %struct.S* @"?s@?$ExportedTemplate@H@@2US@@A", i32 0, i32 0) }, // CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"??__Eselectany1@@YAXXZ", i8* getelementptr inbounds (%struct.S, %struct.S* @"?selectany1@@3US@@A", i32 0, i32 0) }, // CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"??__Eselectany2@@YAXXZ", i8* getelementptr inbounds (%struct.S, %struct.S* @"?selectany2@@3US@@A", i32 0, i32 0) }, -// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"??__E?s@?$ExportedTemplate@H@@2US@@A@@YAXXZ", i8* getelementptr inbounds (%struct.S, %struct.S* @"?s@?$ExportedTemplate@H@@2US@@A", i32 0, i32 0) }, -// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"??__E?foo@?$B@H@@2VA@@A@@YAXXZ", i8* bitcast (%class.A* @"?foo@?$B@H@@2VA@@A" to i8*) }, // CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_microsoft_abi_static_initializers.cpp, i8* null } // CHECK: ] diff --git a/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp b/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp --- a/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp +++ b/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp @@ -29,32 +29,41 @@ // ALL: @_ZN1AIbE1aE ={{.*}} global i32 10 template<> int A::a = 10; -// ALL: @llvm.global_ctors = appending global [8 x { i32, void ()*, i8* }] +// ALL: @llvm.global_ctors = appending global [11 x { i32, void ()*, i8* }] -// ELF: [{ i32, void ()*, i8* } { i32 65535, void ()* @[[unordered1:[^,]*]], i8* bitcast (i32* @_ZN1AIsE1aE to i8*) }, -// MACHO: [{ i32, void ()*, i8* } { i32 65535, void ()* @[[unordered1:[^,]*]], i8* null }, +// ELF: [{ i32, void ()*, i8* } { i32 65535, void ()* @[[unordered10:[^,]*]], i8* bitcast (i32* @_ZN1RILi1EE1aE to i8*) }, +// MACHO: [{ i32, void ()*, i8* } { i32 65535, void ()* @[[unordered10:[^,]*]], i8* null }, -// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered2:[^,]*]], i8* bitcast (i16* @_Z1xIsE to i8*) }, -// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered2:[^,]*]], i8* null }, +// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered9:[^,]*]], i8* bitcast (i32* @_ZN1RILi2EE1aE to i8*) }, +// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered9:[^,]*]], i8* null }, -// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered3:[^,]*]], i8* bitcast (i32* @_ZN2ns1aIiE1iE to i8*) }, -// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered3:[^,]*]], i8* null }, +// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered8:[^,]*]], i8* bitcast (i32* @_ZN1RILi3EE1aE to i8*) }, +// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered8:[^,]*]], i8* null }, -// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered4:[^,]*]], i8* bitcast (i32* @_ZN2ns1b1iIiEE to i8*) }, -// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered4:[^,]*]], i8* null }, +// ALL: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered7:[^,]*]], i8* null }, + +// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered6:[^,]*]], i8* @_Z1xIcE }, +// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered6:[^,]*]], i8* null }, // ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered5:[^,]*]], i8* bitcast (i32* @_ZN1AIvE1aE to i8*) }, // MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered5:[^,]*]], i8* null }, -// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered6:[^,]*]], i8* @_Z1xIcE }, -// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered6:[^,]*]], i8* null }, +// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered4:[^,]*]], i8* bitcast (i32* @_ZN2ns1b1iIiEE to i8*) }, +// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered4:[^,]*]], i8* null }, -// ALL: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered7:[^,]*]], i8* null }, +// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered3:[^,]*]], i8* bitcast (i32* @_ZN2ns1aIiE1iE to i8*) }, +// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered3:[^,]*]], i8* null }, + +// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered2:[^,]*]], i8* bitcast (i16* @_Z1xIsE to i8*) }, +// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered2:[^,]*]], i8* null }, + +// ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered1:[^,]*]], i8* bitcast (i32* @_ZN1AIsE1aE to i8*) }, +// MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered1:[^,]*]], i8* null }, // ALL: { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_static_member_variable_explicit_specialization.cpp, i8* null }] /// llvm.used ensures SHT_INIT_ARRAY in a section group cannot be GCed. -// ELF: @llvm.used = appending global [6 x i8*] [i8* bitcast (i32* @_ZN1AIsE1aE to i8*), i8* bitcast (i16* @_Z1xIsE to i8*), i8* bitcast (i32* @_ZN2ns1aIiE1iE to i8*), i8* bitcast (i32* @_ZN2ns1b1iIiEE to i8*), i8* bitcast (i32* @_ZN1AIvE1aE to i8*), i8* @_Z1xIcE] +// ELF: @llvm.used = appending global [9 x i8*] [i8* bitcast (i32* @_ZN1AIsE1aE to i8*), i8* bitcast (i16* @_Z1xIsE to i8*), i8* bitcast (i32* @_ZN2ns1aIiE1iE to i8*), i8* bitcast (i32* @_ZN2ns1b1iIiEE to i8*), i8* bitcast (i32* @_ZN1AIvE1aE to i8*), i8* @_Z1xIcE, i8* bitcast (i32* @_ZN1RILi3EE1aE to i8*), i8* bitcast (i32* @_ZN1RILi2EE1aE to i8*), i8* bitcast (i32* @_ZN1RILi1EE1aE to i8*)] template int A::a; // Unordered int b = foo(); @@ -94,6 +103,11 @@ } int *use_internal_a = &Internal::a; +template struct R { static int a; }; +template<> int R<0>::a = 0; +template int R::a = R::a + 1; +int f = R<3>::a; + #endif // ALL: define internal void @[[unordered1]]( @@ -131,6 +145,18 @@ // ALL: store {{.*}} @_ZN12_GLOBAL__N_18InternalIiE1aE // ALL: ret +// ALL: define internal void @[[unordered8]]( +// ALL: store {{.*}} @_ZGVN1RILi3EE1aE +// ALL: ret + +// ALL: define internal void @[[unordered9]]( +// ALL: store {{.*}} @_ZGVN1RILi2EE1aE +// ALL: ret + +// ALL: define internal void @[[unordered10]]( +// ALL: store {{.*}} @_ZGVN1RILi1EE1aE +// ALL: ret + // ALL: define internal void @_GLOBAL__sub_I_static_member_variable_explicit_specialization.cpp() // We call unique stubs for every ordered dynamic initializer in the TU. // ALL: call @@ -141,5 +167,6 @@ // ALL: call // ALL: call // ALL: call +// ALL: call // ALL-NOT: call // ALL: ret diff --git a/clang/test/Modules/initializers.cpp b/clang/test/Modules/initializers.cpp --- a/clang/test/Modules/initializers.cpp +++ b/clang/test/Modules/initializers.cpp @@ -154,12 +154,12 @@ // It's OK if the order of the first 6 of these changes. // CHECK: @llvm.global_ctors = appending global -// CHECK-SAME: @[[E_INIT:[^,]*]], {{[^@]*}} @[[E]] -// CHECK-SAME: @[[F_INIT:[^,]*]], {{[^@]*}} @[[F]] -// CHECK-SAME: @[[XA_INIT:[^,]*]], {{[^@]*}} @[[XA]] -// CHECK-SAME: @[[XE_INIT:[^,]*]], {{[^@]*}} @[[XE]] -// CHECK-SAME: @[[XF_INIT:[^,]*]], {{[^@]*}} @[[XF]] // CHECK-SAME: @[[XB_INIT:[^,]*]], {{[^@]*}} @[[XB]] +// CHECK-SAME: @[[XF_INIT:[^,]*]], {{[^@]*}} @[[XF]] +// CHECK-SAME: @[[XE_INIT:[^,]*]], {{[^@]*}} @[[XE]] +// CHECK-SAME: @[[XA_INIT:[^,]*]], {{[^@]*}} @[[XA]] +// CHECK-SAME: @[[F_INIT:[^,]*]], {{[^@]*}} @[[F]] +// CHECK-SAME: @[[E_INIT:[^,]*]], {{[^@]*}} @[[E]] // CHECK-IMPORT-SAME: @[[TU_INIT:[^,]*]], i8* null }] // FIXME: Should this use __cxa_guard_acquire?