jyu2 created this revision.
jyu2 added reviewers: cfe-commits, rnk, majnemer, erichkeane.
Herald added subscribers: llvm-commits, jdoerfert.
Herald added a project: LLVM.
A MS only run time problem, because the init function for template static
member is not getting called when the template static member is not reference.
To be able to evoke the init function, MS put the template static member in the
linker directive section, that cause init function gets call. As Rick
suggest; add template static data member to llvm.used that cause compiler to
emit a similar -include directive into the linker directive section.
//bugs.llvm.org/show_bug.cgi?id=40323
Repository:
rL LLVM
https://reviews.llvm.org/D58160
Files:
lib/CodeGen/CGDeclCXX.cpp
test/CodeGenCXX/microsoft-abi-template-static-init.cpp
Index: test/CodeGenCXX/microsoft-abi-template-static-init.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/microsoft-abi-template-static-init.cpp
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 %s -triple=i686-pc-win32 -fms-extensions -emit-llvm -o - |
FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-pc-win32 -fms-extensions -emit-llvm -o -
| FileCheck %s
+// RUN: %clang_cc1 %s -triple=i686-pc-windows-msvc -fms-extensions -emit-llvm
-o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-pc-windows-msvc -fms-extensions
-emit-llvm -o - | FileCheck %s
+
+struct S {
+ S();
+ ~S();
+};
+
+template <typename T> struct __declspec(dllexport) ExportedTemplate {
+ static S s;
+};
+template <typename T> S ExportedTemplate<T>::s;
+void useExportedTemplate(ExportedTemplate<int> x) {
+ (void)x.s;
+}
+int f();
+namespace selectany_init {
+// MS don't put selectany static var in the linker directive, init routine
+// f() is not getting called if x is not referenced.
+int __declspec(selectany) x = f();
+}
+
+namespace explicit_template_instantiation {
+template <typename T> struct A { static int x; };
+template <typename T> int A<T>::x = f();
+template struct A<int>;
+}
+
+namespace implicit_template_instantiation {
+template <typename T> struct A { static int x; };
+template <typename T> int A<T>::x = f();
+int g() { return A<int>::x; }
+}
+
+
+template <class T>
+struct X_ {
+ static T ioo;
+ static T init();
+};
+template <class T> T X_<T>::ioo = X_<T>::init();
+template struct X_<int>;
+
+template <class T>
+struct X {
+ static T ioo;
+ static T init();
+};
+// template specialized static data don't need in llvm.used,
+// the static init routine get call from _GLOBAL__sub_I_ routines.
+template <> int X<int>::ioo = X<int>::init();
+template struct X<int>;
+// CHECK: @llvm.global_ctors = appending global [6 x { i32, void ()*, i8* }]
[{ i32, void ()*, i8* } { i32 65535, void ()* @"??__Ex@selectany_init@@YAXXZ",
i8* bitcast (i32* @"?x@selectany_init@@3HA" to i8*) }, { i32, void ()*, i8* } {
i32 65535, void ()*
@"??__E?x@?$A@H@explicit_template_instantiation@@2HA@@YAXXZ", i8* bitcast (i32*
@"?x@?$A@H@explicit_template_instantiation@@2HA" to i8*) }, { i32, void ()*,
i8* } { i32 65535, void ()* @"??__E?ioo@?$X_@H@@2HA@@YAXXZ", i8* bitcast (i32*
@"?ioo@?$X_@H@@2HA" to i8*) }, { 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) }, {
i32, void ()*, i8* } { i32 65535, void ()*
@"??__E?x@?$A@H@implicit_template_instantiation@@2HA@@YAXXZ", i8* bitcast (i32*
@"?x@?$A@H@implicit_template_instantiation@@2HA" to i8*) }, { i32, void ()*,
i8* } { i32 65535, void ()*
@_GLOBAL__sub_I_microsoft_abi_template_static_init.cpp, i8* null }]
+// CHECK: @llvm.used = appending global [4 x i8*] [i8* bitcast (i32*
@"?x@?$A@H@explicit_template_instantiation@@2HA" to i8*), i8* bitcast (i32*
@"?ioo@?$X_@H@@2HA" to i8*), i8* getelementptr inbounds (%struct.S, %struct.S*
@"?s@?$ExportedTemplate@H@@2US@@A", i32 0, i32 0), i8* bitcast (i32*
@"?x@?$A@H@implicit_template_instantiation@@2HA" to i8*)], section
"llvm.metadata"
+
Index: lib/CodeGen/CGDeclCXX.cpp
===================================================================
--- lib/CodeGen/CGDeclCXX.cpp
+++ lib/CodeGen/CGDeclCXX.cpp
@@ -481,6 +481,12 @@
// 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()) {
+ // In The MS C++, MS add template static data member in the linker
+ // drective.
+ assert(COMDATKey);
+ addUsedGlobal(COMDATKey);
+ }
} else if (D->hasAttr<SelectAnyAttr>()) {
// SelectAny globals will be comdat-folded. Put the initializer into a
// COMDAT group associated with the global, so the initializers get folded
Index: test/CodeGenCXX/microsoft-abi-template-static-init.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/microsoft-abi-template-static-init.cpp
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 %s -triple=i686-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple=i686-pc-windows-msvc -fms-extensions -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-pc-windows-msvc -fms-extensions -emit-llvm -o - | FileCheck %s
+
+struct S {
+ S();
+ ~S();
+};
+
+template <typename T> struct __declspec(dllexport) ExportedTemplate {
+ static S s;
+};
+template <typename T> S ExportedTemplate<T>::s;
+void useExportedTemplate(ExportedTemplate<int> x) {
+ (void)x.s;
+}
+int f();
+namespace selectany_init {
+// MS don't put selectany static var in the linker directive, init routine
+// f() is not getting called if x is not referenced.
+int __declspec(selectany) x = f();
+}
+
+namespace explicit_template_instantiation {
+template <typename T> struct A { static int x; };
+template <typename T> int A<T>::x = f();
+template struct A<int>;
+}
+
+namespace implicit_template_instantiation {
+template <typename T> struct A { static int x; };
+template <typename T> int A<T>::x = f();
+int g() { return A<int>::x; }
+}
+
+
+template <class T>
+struct X_ {
+ static T ioo;
+ static T init();
+};
+template <class T> T X_<T>::ioo = X_<T>::init();
+template struct X_<int>;
+
+template <class T>
+struct X {
+ static T ioo;
+ static T init();
+};
+// template specialized static data don't need in llvm.used,
+// the static init routine get call from _GLOBAL__sub_I_ routines.
+template <> int X<int>::ioo = X<int>::init();
+template struct X<int>;
+// CHECK: @llvm.global_ctors = appending global [6 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @"??__Ex@selectany_init@@YAXXZ", i8* bitcast (i32* @"?x@selectany_init@@3HA" to i8*) }, { i32, void ()*, i8* } { i32 65535, void ()* @"??__E?x@?$A@H@explicit_template_instantiation@@2HA@@YAXXZ", i8* bitcast (i32* @"?x@?$A@H@explicit_template_instantiation@@2HA" to i8*) }, { i32, void ()*, i8* } { i32 65535, void ()* @"??__E?ioo@?$X_@H@@2HA@@YAXXZ", i8* bitcast (i32* @"?ioo@?$X_@H@@2HA" to i8*) }, { 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) }, { i32, void ()*, i8* } { i32 65535, void ()* @"??__E?x@?$A@H@implicit_template_instantiation@@2HA@@YAXXZ", i8* bitcast (i32* @"?x@?$A@H@implicit_template_instantiation@@2HA" to i8*) }, { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_microsoft_abi_template_static_init.cpp, i8* null }]
+// CHECK: @llvm.used = appending global [4 x i8*] [i8* bitcast (i32* @"?x@?$A@H@explicit_template_instantiation@@2HA" to i8*), i8* bitcast (i32* @"?ioo@?$X_@H@@2HA" to i8*), i8* getelementptr inbounds (%struct.S, %struct.S* @"?s@?$ExportedTemplate@H@@2US@@A", i32 0, i32 0), i8* bitcast (i32* @"?x@?$A@H@implicit_template_instantiation@@2HA" to i8*)], section "llvm.metadata"
+
Index: lib/CodeGen/CGDeclCXX.cpp
===================================================================
--- lib/CodeGen/CGDeclCXX.cpp
+++ lib/CodeGen/CGDeclCXX.cpp
@@ -481,6 +481,12 @@
// 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()) {
+ // In The MS C++, MS add template static data member in the linker
+ // drective.
+ assert(COMDATKey);
+ addUsedGlobal(COMDATKey);
+ }
} else if (D->hasAttr<SelectAnyAttr>()) {
// SelectAny globals will be comdat-folded. Put the initializer into a
// COMDAT group associated with the global, so the initializers get folded
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits