2015-05-07 14:15:46 +08:00
|
|
|
// RUN: %clang_cc1 -fms-extensions -fno-threadsafe-statics -emit-llvm %s -o - -mconstructor-aliases -triple=i386-pc-win32 | FileCheck %s
|
2012-05-01 14:13:13 +08:00
|
|
|
|
2014-09-11 03:28:48 +08:00
|
|
|
// CHECK: @llvm.global_ctors = appending global [5 x { i32, void ()*, i8* }] [
|
2015-03-14 02:21:46 +08:00
|
|
|
// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"\01??__Eselectany1@@YAXXZ", i8* getelementptr inbounds (%struct.S, %struct.S* @"\01?selectany1@@3US@@A", i32 0, i32 0) },
|
|
|
|
// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"\01??__Eselectany2@@YAXXZ", i8* getelementptr inbounds (%struct.S, %struct.S* @"\01?selectany2@@3US@@A", i32 0, i32 0) },
|
|
|
|
// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"\01??__Es@?$ExportedTemplate@H@@2US@@A@YAXXZ", i8* getelementptr inbounds (%struct.S, %struct.S* @"\01?s@?$ExportedTemplate@H@@2US@@A", i32 0, i32 0) },
|
2014-09-11 03:28:48 +08:00
|
|
|
// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"\01??__Efoo@?$B@H@@2VA@@A@YAXXZ", i8* bitcast (%class.A* @"\01?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: ]
|
2013-08-23 04:07:45 +08:00
|
|
|
|
2012-05-01 14:13:13 +08:00
|
|
|
struct S {
|
2013-09-11 04:14:30 +08:00
|
|
|
S();
|
|
|
|
~S();
|
|
|
|
};
|
|
|
|
|
|
|
|
S s;
|
2012-05-01 14:13:13 +08:00
|
|
|
|
2014-05-24 05:13:45 +08:00
|
|
|
// CHECK: define internal void @"\01??__Es@@YAXXZ"()
|
|
|
|
// CHECK: call x86_thiscallcc %struct.S* @"\01??0S@@QAE@XZ"
|
2013-09-11 04:14:30 +08:00
|
|
|
// CHECK: call i32 @atexit(void ()* @"\01??__Fs@@YAXXZ")
|
2012-05-01 14:13:13 +08:00
|
|
|
// CHECK: ret void
|
|
|
|
|
2014-05-24 05:13:45 +08:00
|
|
|
// CHECK: define internal void @"\01??__Fs@@YAXXZ"()
|
2012-07-12 17:50:54 +08:00
|
|
|
// CHECK: call x86_thiscallcc void @"\01??1S@@QAE@XZ"
|
2012-05-01 14:13:13 +08:00
|
|
|
// CHECK: ret void
|
|
|
|
|
2014-09-11 03:28:48 +08:00
|
|
|
// These globals should have initializers comdat associative with the global.
|
|
|
|
// See @llvm.global_ctors above.
|
2014-04-24 02:22:11 +08:00
|
|
|
__declspec(selectany) S selectany1;
|
|
|
|
__declspec(selectany) S selectany2;
|
2015-01-17 00:04:45 +08:00
|
|
|
// CHECK: define linkonce_odr void @"\01??__Eselectany1@@YAXXZ"() {{.*}} comdat
|
2014-05-24 05:13:45 +08:00
|
|
|
// CHECK-NOT: @"\01??_Bselectany1
|
|
|
|
// CHECK: call x86_thiscallcc %struct.S* @"\01??0S@@QAE@XZ"
|
2014-04-24 02:22:11 +08:00
|
|
|
// CHECK: ret void
|
2015-01-17 00:04:45 +08:00
|
|
|
// CHECK: define linkonce_odr void @"\01??__Eselectany2@@YAXXZ"() {{.*}} comdat
|
2014-05-24 05:13:45 +08:00
|
|
|
// CHECK-NOT: @"\01??_Bselectany2
|
|
|
|
// CHECK: call x86_thiscallcc %struct.S* @"\01??0S@@QAE@XZ"
|
2014-04-24 02:22:11 +08:00
|
|
|
// CHECK: ret void
|
|
|
|
|
2014-09-11 03:28:48 +08:00
|
|
|
// The implicitly instantiated static data member should have initializer
|
|
|
|
// comdat associative with the global.
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-09-11 04:14:30 +08:00
|
|
|
void StaticLocal() {
|
|
|
|
static S TheS;
|
|
|
|
}
|
2014-09-11 03:28:48 +08:00
|
|
|
|
2013-09-11 04:14:30 +08:00
|
|
|
// CHECK-LABEL: define void @"\01?StaticLocal@@YAXXZ"()
|
2015-02-28 05:19:58 +08:00
|
|
|
// CHECK: load i32, i32* @"\01?$S1@?1??StaticLocal@@YAXXZ@4IA"
|
2014-10-05 14:44:53 +08:00
|
|
|
// CHECK: store i32 {{.*}}, i32* @"\01?$S1@?1??StaticLocal@@YAXXZ@4IA"
|
2013-09-11 04:14:30 +08:00
|
|
|
// CHECK: ret
|
|
|
|
|
|
|
|
void MultipleStatics() {
|
|
|
|
static S S1;
|
|
|
|
static S S2;
|
|
|
|
static S S3;
|
|
|
|
static S S4;
|
|
|
|
static S S5;
|
|
|
|
static S S6;
|
|
|
|
static S S7;
|
|
|
|
static S S8;
|
|
|
|
static S S9;
|
|
|
|
static S S10;
|
|
|
|
static S S11;
|
|
|
|
static S S12;
|
|
|
|
static S S13;
|
|
|
|
static S S14;
|
|
|
|
static S S15;
|
|
|
|
static S S16;
|
|
|
|
static S S17;
|
|
|
|
static S S18;
|
|
|
|
static S S19;
|
|
|
|
static S S20;
|
|
|
|
static S S21;
|
|
|
|
static S S22;
|
|
|
|
static S S23;
|
|
|
|
static S S24;
|
|
|
|
static S S25;
|
|
|
|
static S S26;
|
|
|
|
static S S27;
|
|
|
|
static S S28;
|
|
|
|
static S S29;
|
|
|
|
static S S30;
|
|
|
|
static S S31;
|
|
|
|
static S S32;
|
|
|
|
static S S33;
|
|
|
|
static S S34;
|
|
|
|
static S S35;
|
|
|
|
}
|
|
|
|
// CHECK-LABEL: define void @"\01?MultipleStatics@@YAXXZ"()
|
2015-02-28 05:19:58 +08:00
|
|
|
// CHECK: load i32, i32* @"\01?$S1@?1??MultipleStatics@@YAXXZ@4IA"
|
2013-09-11 04:14:30 +08:00
|
|
|
// CHECK: and i32 {{.*}}, 1
|
|
|
|
// CHECK: and i32 {{.*}}, 2
|
|
|
|
// CHECK: and i32 {{.*}}, 4
|
|
|
|
// CHECK: and i32 {{.*}}, 8
|
|
|
|
// CHECK: and i32 {{.*}}, 16
|
|
|
|
// ...
|
|
|
|
// CHECK: and i32 {{.*}}, -2147483648
|
2015-05-13 00:48:43 +08:00
|
|
|
// CHECK: load i32, i32* @"\01?$S1@?1??MultipleStatics@@YAXXZ@4IA.1"
|
2013-09-11 04:14:30 +08:00
|
|
|
// CHECK: and i32 {{.*}}, 1
|
|
|
|
// CHECK: and i32 {{.*}}, 2
|
|
|
|
// CHECK: and i32 {{.*}}, 4
|
|
|
|
// CHECK: ret
|
|
|
|
|
2012-05-01 14:13:13 +08:00
|
|
|
// Force WeakODRLinkage by using templates
|
|
|
|
class A {
|
|
|
|
public:
|
|
|
|
A() {}
|
|
|
|
~A() {}
|
2014-05-24 05:13:45 +08:00
|
|
|
int a;
|
2012-05-01 14:13:13 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
class B {
|
|
|
|
public:
|
|
|
|
static A foo;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T> A B<T>::foo;
|
|
|
|
|
2013-09-11 04:14:30 +08:00
|
|
|
inline S &UnreachableStatic() {
|
|
|
|
if (0) {
|
|
|
|
static S s; // bit 1
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
static S s; // bit 2
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2015-01-17 00:02:03 +08:00
|
|
|
// CHECK-LABEL: define linkonce_odr dereferenceable({{[0-9]+}}) %struct.S* @"\01?UnreachableStatic@@YAAAUS@@XZ"() {{.*}} comdat
|
2013-09-11 04:14:30 +08:00
|
|
|
// CHECK: and i32 {{.*}}, 2
|
|
|
|
// CHECK: or i32 {{.*}}, 2
|
|
|
|
// CHECK: ret
|
|
|
|
|
|
|
|
inline S &getS() {
|
|
|
|
static S TheS;
|
|
|
|
return TheS;
|
|
|
|
}
|
|
|
|
|
2015-01-17 00:02:03 +08:00
|
|
|
// CHECK-LABEL: define linkonce_odr dereferenceable({{[0-9]+}}) %struct.S* @"\01?getS@@YAAAUS@@XZ"() {{.*}} comdat
|
2015-02-28 05:19:58 +08:00
|
|
|
// CHECK: load i32, i32* @"\01??_B?1??getS@@YAAAUS@@XZ@51"
|
2013-09-11 04:14:30 +08:00
|
|
|
// CHECK: and i32 {{.*}}, 1
|
2017-07-27 06:01:09 +08:00
|
|
|
// CHECK: icmp eq i32 {{.*}}, 0
|
2013-09-11 04:14:30 +08:00
|
|
|
// CHECK: br i1
|
|
|
|
// init:
|
|
|
|
// CHECK: or i32 {{.*}}, 1
|
|
|
|
// CHECK: store i32 {{.*}}, i32* @"\01??_B?1??getS@@YAAAUS@@XZ@51"
|
|
|
|
// CHECK: call x86_thiscallcc %struct.S* @"\01??0S@@QAE@XZ"(%struct.S* @"\01?TheS@?1??getS@@YAAAUS@@XZ@4U2@A")
|
|
|
|
// CHECK: call i32 @atexit(void ()* @"\01??__FTheS@?1??getS@@YAAAUS@@XZ@YAXXZ")
|
|
|
|
// CHECK: br label
|
|
|
|
// init.end:
|
|
|
|
// CHECK: ret %struct.S* @"\01?TheS@?1??getS@@YAAAUS@@XZ@4U2@A"
|
|
|
|
|
2014-06-17 08:00:18 +08:00
|
|
|
inline int enum_in_function() {
|
2015-01-17 00:02:03 +08:00
|
|
|
// CHECK-LABEL: define linkonce_odr i32 @"\01?enum_in_function@@YAHXZ"() {{.*}} comdat
|
2014-06-17 08:00:18 +08:00
|
|
|
static enum e { foo, bar, baz } x;
|
|
|
|
// CHECK: @"\01?x@?1??enum_in_function@@YAHXZ@4W4e@?1??1@YAHXZ@A"
|
|
|
|
static int y;
|
|
|
|
// CHECK: @"\01?y@?1??enum_in_function@@YAHXZ@4HA"
|
|
|
|
return x + y;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct T {
|
|
|
|
enum e { foo, bar, baz };
|
|
|
|
int enum_in_struct() {
|
2015-01-17 00:02:03 +08:00
|
|
|
// CHECK-LABEL: define linkonce_odr x86_thiscallcc i32 @"\01?enum_in_struct@T@@QAEHXZ"({{.*}}) {{.*}} comdat
|
2014-06-17 08:00:18 +08:00
|
|
|
static int x;
|
|
|
|
// CHECK: @"\01?x@?1??enum_in_struct@T@@QAEHXZ@4HA"
|
|
|
|
return x++;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-06-17 08:09:05 +08:00
|
|
|
inline int switch_test(int x) {
|
2015-01-17 00:02:03 +08:00
|
|
|
// CHECK-LABEL: define linkonce_odr i32 @"\01?switch_test@@YAHH@Z"(i32 %x) {{.*}} comdat
|
2014-06-17 08:09:05 +08:00
|
|
|
switch (x) {
|
|
|
|
static int a;
|
|
|
|
// CHECK: @"\01?a@?3??switch_test@@YAHH@Z@4HA"
|
|
|
|
case 0:
|
|
|
|
a++;
|
|
|
|
return 1;
|
|
|
|
case 1:
|
|
|
|
static int b;
|
|
|
|
// CHECK: @"\01?b@?3??switch_test@@YAHH@Z@4HA"
|
|
|
|
return b++;
|
|
|
|
case 2: {
|
|
|
|
static int c;
|
|
|
|
// CHECK: @"\01?c@?4??switch_test@@YAHH@Z@4HA"
|
|
|
|
return b + c++;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
int f();
|
|
|
|
inline void switch_test2() {
|
2015-01-17 00:02:03 +08:00
|
|
|
// CHECK-LABEL: define linkonce_odr void @"\01?switch_test2@@YAXXZ"() {{.*}} comdat
|
2014-06-17 08:09:05 +08:00
|
|
|
// CHECK: @"\01?x@?2??switch_test2@@YAXXZ@4HA"
|
|
|
|
switch (1) default: static int x = f();
|
|
|
|
}
|
|
|
|
|
2014-06-18 09:21:33 +08:00
|
|
|
namespace DynamicDLLImportInitVSMangling {
|
|
|
|
// Failing to pop the ExprEvalContexts when instantiating a dllimport var with
|
|
|
|
// dynamic initializer would cause subsequent static local numberings to be
|
|
|
|
// incorrect.
|
|
|
|
struct NonPOD { NonPOD(); };
|
|
|
|
template <typename T> struct A { static NonPOD x; };
|
|
|
|
template <typename T> NonPOD A<T>::x;
|
|
|
|
template struct __declspec(dllimport) A<int>;
|
|
|
|
|
|
|
|
inline int switch_test3() {
|
2015-01-17 00:02:03 +08:00
|
|
|
// CHECK-LABEL: define linkonce_odr i32 @"\01?switch_test3@DynamicDLLImportInitVSMangling@@YAHXZ"() {{.*}} comdat
|
2014-06-18 09:21:33 +08:00
|
|
|
static int local;
|
|
|
|
// CHECK: @"\01?local@?1??switch_test3@DynamicDLLImportInitVSMangling@@YAHXZ@4HA"
|
|
|
|
return local++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-01 14:13:13 +08:00
|
|
|
void force_usage() {
|
2013-09-11 04:14:30 +08:00
|
|
|
UnreachableStatic();
|
|
|
|
getS();
|
2012-05-01 14:13:13 +08:00
|
|
|
(void)B<int>::foo; // (void) - force usage
|
2014-06-17 08:00:18 +08:00
|
|
|
enum_in_function();
|
|
|
|
(void)&T::enum_in_struct;
|
2014-06-17 08:09:05 +08:00
|
|
|
switch_test(1);
|
|
|
|
switch_test2();
|
2014-06-18 09:21:33 +08:00
|
|
|
DynamicDLLImportInitVSMangling::switch_test3();
|
2012-05-01 14:13:13 +08:00
|
|
|
}
|
|
|
|
|
2015-01-17 00:04:45 +08:00
|
|
|
// CHECK: define linkonce_odr void @"\01??__Efoo@?$B@H@@2VA@@A@YAXXZ"() {{.*}} comdat
|
2014-05-24 05:13:45 +08:00
|
|
|
// CHECK-NOT: and
|
|
|
|
// CHECK-NOT: ?_Bfoo@
|
|
|
|
// CHECK: call x86_thiscallcc %class.A* @"\01??0A@@QAE@XZ"
|
2014-03-07 03:10:27 +08:00
|
|
|
// CHECK: call i32 @atexit(void ()* @"\01??__Ffoo@?$B@H@@2VA@@A@YAXXZ")
|
2012-05-01 14:13:13 +08:00
|
|
|
// CHECK: ret void
|
|
|
|
|
2015-01-17 00:02:03 +08:00
|
|
|
// CHECK: define linkonce_odr x86_thiscallcc %class.A* @"\01??0A@@QAE@XZ"({{.*}}) {{.*}} comdat
|
2012-05-01 14:13:13 +08:00
|
|
|
|
2015-01-17 00:02:03 +08:00
|
|
|
// CHECK: define linkonce_odr x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}}) {{.*}} comdat
|
2012-05-01 14:13:13 +08:00
|
|
|
|
2014-03-07 03:10:27 +08:00
|
|
|
// CHECK: define internal void @"\01??__Ffoo@?$B@H@@2VA@@A@YAXXZ"
|
2012-07-12 17:50:54 +08:00
|
|
|
// CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"{{.*}}foo
|
2012-05-01 14:13:13 +08:00
|
|
|
// CHECK: ret void
|
|
|
|
|
2014-05-24 05:13:45 +08:00
|
|
|
// CHECK: define internal void @_GLOBAL__sub_I_microsoft_abi_static_initializers.cpp()
|
2013-09-11 04:43:12 +08:00
|
|
|
// CHECK: call void @"\01??__Es@@YAXXZ"()
|
2012-05-01 14:13:13 +08:00
|
|
|
// CHECK: ret void
|