Index: clang/lib/CodeGen/CGDeclCXX.cpp =================================================================== --- clang/lib/CodeGen/CGDeclCXX.cpp +++ clang/lib/CodeGen/CGDeclCXX.cpp @@ -517,19 +517,24 @@ PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn)); } else if (isTemplateInstantiation(D->getTemplateSpecializationKind()) || getContext().GetGVALinkageForVariable(D) == GVA_DiscardableODR) { - // C++ [basic.start.init]p2: - // Definitions of explicitly specialized class template static data - // members have ordered initialization. Other class template static data - // members (i.e., implicitly or explicitly instantiated specializations) - // have unordered initialization. - // - // As a consequence, we can put them into their own llvm.global_ctors entry. - // - // If the global is externally visible, 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, COMDATKey); + if (getCXXABI().useSinitAndSterm()) + CXXGlobalInits.push_back(Fn); + else + // C++ [basic.start.init]p2: + // Definitions of explicitly specialized class template static data + // members have ordered initialization. Other class template static + // data members (i.e., implicitly or explicitly instantiated + // specializations) have unordered initialization. + // + // As a consequence, we can put them into their own llvm.global_ctors + // entry. + // + // If the global is externally visible, 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, COMDATKey); + if (getTarget().getCXXABI().isMicrosoft() && COMDATKey) { // In The MS C++, MS add template static data member in the linker // drective. Index: clang/test/CodeGenCXX/aix-static-init-temp-spec-and-inline-var.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/aix-static-init-temp-spec-and-inline-var.cpp @@ -0,0 +1,238 @@ +// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -S -emit-llvm -x c++ \ +// RUN: -std=c++2a < %s | \ +// RUN: FileCheck --check-prefixes=CHECK,CHECK32 %s + +// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -S -emit-llvm -x c++ \ +// RUN: -std=c++2a < %s | \ +// RUN: FileCheck --check-prefixes=CHECK,CHECK64 %s + +namespace test1 { + struct Test1 { + Test1(int) {} + ~Test1() {} + }; + + Test1 t0 = 2; + template Test1 t1 = 2; + inline Test1 t2 = 2; + + void foo() { + (void) &t1; + } +} // namespace test1 + +namespace test2 { + template + struct A { + A() {} + ~A() {} + static A instance; + }; + + template A A::instance; + template A<> A<>::instance; + + A &bar() { + A *a = new A; + return *a; + } + template<> A A::instance = bar(); +} // namespace test2 + +// CHECK: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__sinit80000000_clang_32add9385a76444cd9d0fab0fb83307b, i8* null }] +// CHECK: @llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__sterm80000000_clang_32add9385a76444cd9d0fab0fb83307b, i8* null }] + +// CHECK: define internal void @__cxx_global_var_init() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK32: call void @_ZN5test15Test1C1Ei(%"struct.test1::Test1"* @_ZN5test12t0E, i32 2) +// CHECK64: call void @_ZN5test15Test1C1Ei(%"struct.test1::Test1"* @_ZN5test12t0E, i32 signext 2) +// CHECK: %0 = call i32 @atexit(void ()* @__dtor__ZN5test12t0E) +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__dtor__ZN5test12t0E() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: call void @_ZN5test15Test1D1Ev(%"struct.test1::Test1"* @_ZN5test12t0E) +// CHECK: ret void +// CHECK: } + +// CHECK: declare i32 @atexit(void ()*) + +// CHECK: define internal void @__finalize__ZN5test12t0E() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: %0 = call i32 @unatexit(void ()* @__dtor__ZN5test12t0E) +// CHECK: %needs_destruct = icmp eq i32 %0, 0 +// CHECK: br i1 %needs_destruct, label %destruct.call, label %destruct.end + +// CHECK: destruct.call: +// CHECK: call void @__dtor__ZN5test12t0E() +// CHECK: br label %destruct.end + +// CHECK: destruct.end: + //CHECK: ret void +// CHECK: } + +// CHECK: declare i32 @unatexit(void ()*) + +// CHECK: define internal void @__cxx_global_var_init.1() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: %0 = load atomic i8, i8* bitcast (i64* @_ZGVN5test12t2E to i8*) acquire +// CHECK: %guard.uninitialized = icmp eq i8 %0, 0 +// CHECK: br i1 %guard.uninitialized, label %init.check, label %init.end + +// CHECK: init.check: + //CHECK: %1 = call i32 @__cxa_guard_acquire(i64* @_ZGVN5test12t2E) +// CHECK: %tobool = icmp ne i32 %1, 0 +// CHECK: br i1 %tobool, label %init, label %init.end + +// CHECK: init: +// CHECK32: call void @_ZN5test15Test1C1Ei(%"struct.test1::Test1"* @_ZN5test12t2E, i32 2) +// CHECK64: call void @_ZN5test15Test1C1Ei(%"struct.test1::Test1"* @_ZN5test12t2E, i32 signext 2) +// CHECK: %2 = call i32 @atexit(void ()* @__dtor__ZN5test12t2E) +// CHECK: call void @__cxa_guard_release(i64* @_ZGVN5test12t2E) +// CHECK: br label %init.end + +// CHECK: init.end: +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__dtor__ZN5test12t2E() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: call void @_ZN5test15Test1D1Ev(%"struct.test1::Test1"* @_ZN5test12t2E) +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__finalize__ZN5test12t2E() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: %0 = call i32 @unatexit(void ()* @__dtor__ZN5test12t2E) +// CHECK: %needs_destruct = icmp eq i32 %0, 0 +// CHECK: br i1 %needs_destruct, label %destruct.call, label %destruct.end + +// CHECK: destruct.call: +// CHECK: call void @__dtor__ZN5test12t2E() +// CHECK: br label %destruct.end + +// CHECK: destruct.end: +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__cxx_global_var_init.2() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: %0 = load i8, i8* bitcast (i64* @_ZGVN5test21AIvE8instanceE to i8*) +// CHECK: %guard.uninitialized = icmp eq i8 %0, 0 +// CHECK: br i1 %guard.uninitialized, label %init.check, label %init.end + +// CHECK: init.check: +// CHECK: call void @_ZN5test21AIvEC1Ev(%"struct.test2::A"* @_ZN5test21AIvE8instanceE) +// CHECK: %1 = call i32 @atexit(void ()* @__dtor__ZN5test21AIvE8instanceE) #2 +// CHECK: store i64 1, i64* @_ZGVN5test21AIvE8instanceE, align 8 +// CHECK: br label %init.end + +// CHECK: init.end: +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__dtor__ZN5test21AIvE8instanceE() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: call void @_ZN5test21AIvED1Ev(%"struct.test2::A"* @_ZN5test21AIvE8instanceE) +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__finalize__ZN5test21AIvE8instanceE() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: %0 = call i32 @unatexit(void ()* @__dtor__ZN5test21AIvE8instanceE) +// CHECK: %needs_destruct = icmp eq i32 %0, 0 +// CHECK: br i1 %needs_destruct, label %destruct.call, label %destruct.end + +// CHECK: destruct.call: +// CHECK: call void @__dtor__ZN5test21AIvE8instanceE() +// CHECK: br label %destruct.end + +// CHECK: destruct.end: +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__cxx_global_var_init.3() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: %call = call nonnull align 1 dereferenceable(1) %"struct.test2::A.0"* @_ZN5test23barEv() +// CHECK: %0 = call i32 @atexit(void ()* @__dtor__ZN5test21AIiE8instanceE) +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__dtor__ZN5test21AIiE8instanceE() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: call void @_ZN5test21AIiED1Ev(%"struct.test2::A.0"* @_ZN5test21AIiE8instanceE) +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__finalize__ZN5test21AIiE8instanceE() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: %0 = call i32 @unatexit(void ()* @__dtor__ZN5test21AIiE8instanceE) +// CHECK: %needs_destruct = icmp eq i32 %0, 0 +// CHECK: br i1 %needs_destruct, label %destruct.call, label %destruct.end + +// CHECK: destruct.call: +// CHECK: call void @__dtor__ZN5test21AIiE8instanceE() +// CHECK: br label %destruct.end + +// CHECK: destruct.end: +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__cxx_global_var_init.4() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: %0 = load i8, i8* bitcast (i64* @_ZGVN5test12t1IiEE to i8*) +// CHECK: %guard.uninitialized = icmp eq i8 %0, 0 +// CHECK: br i1 %guard.uninitialized, label %init.check, label %init.end + +// CHECK: init.check: +// CHECK32: call void @_ZN5test15Test1C1Ei(%"struct.test1::Test1"* @_ZN5test12t1IiEE, i32 2) +// CHECK64: call void @_ZN5test15Test1C1Ei(%"struct.test1::Test1"* @_ZN5test12t1IiEE, i32 signext 2) +// CHECK: %1 = call i32 @atexit(void ()* @__dtor__ZN5test12t1IiEE) +// CHECK: store i64 1, i64* @_ZGVN5test12t1IiEE +// CHECK: br label %init.end + +// CHECK: init.end: +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__dtor__ZN5test12t1IiEE() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: call void @_ZN5test15Test1D1Ev(%"struct.test1::Test1"* @_ZN5test12t1IiEE) +// CHECK: ret void +// CHECK: } + +// CHECK: define internal void @__finalize__ZN5test12t1IiEE() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: %0 = call i32 @unatexit(void ()* @__dtor__ZN5test12t1IiEE) +// CHECK: %needs_destruct = icmp eq i32 %0, 0 +// CHECK: br i1 %needs_destruct, label %destruct.call, label %destruct.end + +// CHECK: destruct.call: +// CHECK: call void @__dtor__ZN5test12t1IiEE() +// CHECK: br label %destruct.end + +// CHECK: destruct.end: +// CHECK: ret void +// CHECK: } + +// CHECK: define void @__sinit80000000_clang_32add9385a76444cd9d0fab0fb83307b() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: call void @__cxx_global_var_init() +// CHECK: call void @__cxx_global_var_init.1() +// CHECK: call void @__cxx_global_var_init.2() +// CHECK: call void @__cxx_global_var_init.3() +// CHECK: call void @__cxx_global_var_init.4() +// CHECK: ret void +// CHECK: } + +// CHECK: ; Function Attrs: nounwind +// CHECK: define void @__sterm80000000_clang_32add9385a76444cd9d0fab0fb83307b() [[ATTR:#[0-9]+]] { +// CHECK: entry: +// CHECK: call void @__finalize__ZN5test12t1IiEE() +// CHECK: call void @__finalize__ZN5test21AIiE8instanceE() +// CHECK: call void @__finalize__ZN5test21AIvE8instanceE() +// CHECK: call void @__finalize__ZN5test12t2E() +// CHECK: call void @__finalize__ZN5test12t0E() +// CHECK: ret void +// CHECK: }