| // RUN: %clang_cc1 -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 ()* @"??__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 ()* @"??__Es@?$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 ()* @"??__Efoo@?$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: ] |
| |
| struct S { |
| S(); |
| ~S(); |
| }; |
| |
| S s; |
| |
| // CHECK: define internal void @"??__Es@@YAXXZ"() |
| // CHECK: call x86_thiscallcc %struct.S* @"??0S@@QAE@XZ" |
| // CHECK: call i32 @atexit(void ()* @"??__Fs@@YAXXZ") |
| // CHECK: ret void |
| |
| // CHECK: define internal void @"??__Fs@@YAXXZ"() |
| // CHECK: call x86_thiscallcc void @"??1S@@QAE@XZ" |
| // CHECK: ret void |
| |
| // These globals should have initializers comdat associative with the global. |
| // See @llvm.global_ctors above. |
| __declspec(selectany) S selectany1; |
| __declspec(selectany) S selectany2; |
| // CHECK: define linkonce_odr dso_local void @"??__Eselectany1@@YAXXZ"() {{.*}} comdat |
| // CHECK-NOT: @"??_Bselectany1 |
| // CHECK: call x86_thiscallcc %struct.S* @"??0S@@QAE@XZ" |
| // CHECK: ret void |
| // CHECK: define linkonce_odr dso_local void @"??__Eselectany2@@YAXXZ"() {{.*}} comdat |
| // CHECK-NOT: @"??_Bselectany2 |
| // CHECK: call x86_thiscallcc %struct.S* @"??0S@@QAE@XZ" |
| // CHECK: ret void |
| |
| // 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; |
| } |
| |
| void StaticLocal() { |
| static S TheS; |
| } |
| |
| // CHECK-LABEL: define dso_local void @"?StaticLocal@@YAXXZ"() |
| // CHECK: load i32, i32* @"?$S1@?1??StaticLocal@@YAXXZ@4IA" |
| // CHECK: store i32 {{.*}}, i32* @"?$S1@?1??StaticLocal@@YAXXZ@4IA" |
| // 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 dso_local void @"?MultipleStatics@@YAXXZ"() |
| // CHECK: load i32, i32* @"?$S1@?1??MultipleStatics@@YAXXZ@4IA" |
| // CHECK: and i32 {{.*}}, 1 |
| // CHECK: and i32 {{.*}}, 2 |
| // CHECK: and i32 {{.*}}, 4 |
| // CHECK: and i32 {{.*}}, 8 |
| // CHECK: and i32 {{.*}}, 16 |
| // ... |
| // CHECK: and i32 {{.*}}, -2147483648 |
| // CHECK: load i32, i32* @"?$S1@?1??MultipleStatics@@YAXXZ@4IA.1" |
| // CHECK: and i32 {{.*}}, 1 |
| // CHECK: and i32 {{.*}}, 2 |
| // CHECK: and i32 {{.*}}, 4 |
| // CHECK: ret |
| |
| // Force WeakODRLinkage by using templates |
| class A { |
| public: |
| A() {} |
| ~A() {} |
| int a; |
| }; |
| |
| template<typename T> |
| class B { |
| public: |
| static A foo; |
| }; |
| |
| template<typename T> A B<T>::foo; |
| |
| inline S &UnreachableStatic() { |
| if (0) { |
| static S s; // bit 1 |
| return s; |
| } |
| static S s; // bit 2 |
| return s; |
| } |
| |
| // CHECK-LABEL: define linkonce_odr dso_local dereferenceable({{[0-9]+}}) %struct.S* @"?UnreachableStatic@@YAAAUS@@XZ"() {{.*}} comdat |
| // CHECK: and i32 {{.*}}, 2 |
| // CHECK: or i32 {{.*}}, 2 |
| // CHECK: ret |
| |
| inline S &getS() { |
| static S TheS; |
| return TheS; |
| } |
| |
| // CHECK-LABEL: define linkonce_odr dso_local dereferenceable({{[0-9]+}}) %struct.S* @"?getS@@YAAAUS@@XZ"() {{.*}} comdat |
| // CHECK: load i32, i32* @"??_B?1??getS@@YAAAUS@@XZ@51" |
| // CHECK: and i32 {{.*}}, 1 |
| // CHECK: icmp eq i32 {{.*}}, 0 |
| // CHECK: br i1 |
| // init: |
| // CHECK: or i32 {{.*}}, 1 |
| // CHECK: store i32 {{.*}}, i32* @"??_B?1??getS@@YAAAUS@@XZ@51" |
| // CHECK: call x86_thiscallcc %struct.S* @"??0S@@QAE@XZ"(%struct.S* @"?TheS@?1??getS@@YAAAUS@@XZ@4U2@A") |
| // CHECK: call i32 @atexit(void ()* @"??__FTheS@?1??getS@@YAAAUS@@XZ@YAXXZ") |
| // CHECK: br label |
| // init.end: |
| // CHECK: ret %struct.S* @"?TheS@?1??getS@@YAAAUS@@XZ@4U2@A" |
| |
| inline int enum_in_function() { |
| // CHECK-LABEL: define linkonce_odr dso_local i32 @"?enum_in_function@@YAHXZ"() {{.*}} comdat |
| static enum e { foo, bar, baz } x; |
| // CHECK: @"?x@?1??enum_in_function@@YAHXZ@4W4e@?1??1@YAHXZ@A" |
| static int y; |
| // CHECK: @"?y@?1??enum_in_function@@YAHXZ@4HA" |
| return x + y; |
| }; |
| |
| struct T { |
| enum e { foo, bar, baz }; |
| int enum_in_struct() { |
| // CHECK-LABEL: define linkonce_odr dso_local x86_thiscallcc i32 @"?enum_in_struct@T@@QAEHXZ"({{.*}}) {{.*}} comdat |
| static int x; |
| // CHECK: @"?x@?1??enum_in_struct@T@@QAEHXZ@4HA" |
| return x++; |
| } |
| }; |
| |
| inline int switch_test(int x) { |
| // CHECK-LABEL: define linkonce_odr dso_local i32 @"?switch_test@@YAHH@Z"(i32 %x) {{.*}} comdat |
| switch (x) { |
| static int a; |
| // CHECK: @"?a@?3??switch_test@@YAHH@Z@4HA" |
| case 0: |
| a++; |
| return 1; |
| case 1: |
| static int b; |
| // CHECK: @"?b@?3??switch_test@@YAHH@Z@4HA" |
| return b++; |
| case 2: { |
| static int c; |
| // CHECK: @"?c@?4??switch_test@@YAHH@Z@4HA" |
| return b + c++; |
| } |
| }; |
| } |
| |
| int f(); |
| inline void switch_test2() { |
| // CHECK-LABEL: define linkonce_odr dso_local void @"?switch_test2@@YAXXZ"() {{.*}} comdat |
| // CHECK: @"?x@?2??switch_test2@@YAXXZ@4HA" |
| switch (1) default: static int x = f(); |
| } |
| |
| 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() { |
| // CHECK-LABEL: define linkonce_odr dso_local i32 @"?switch_test3@DynamicDLLImportInitVSMangling@@YAHXZ"() {{.*}} comdat |
| static int local; |
| // CHECK: @"?local@?1??switch_test3@DynamicDLLImportInitVSMangling@@YAHXZ@4HA" |
| return local++; |
| } |
| } |
| |
| void force_usage() { |
| UnreachableStatic(); |
| getS(); |
| (void)B<int>::foo; // (void) - force usage |
| enum_in_function(); |
| (void)&T::enum_in_struct; |
| switch_test(1); |
| switch_test2(); |
| DynamicDLLImportInitVSMangling::switch_test3(); |
| } |
| |
| // CHECK: define linkonce_odr dso_local void @"??__Efoo@?$B@H@@2VA@@A@YAXXZ"() {{.*}} comdat |
| // CHECK-NOT: and |
| // CHECK-NOT: ?_Bfoo@ |
| // CHECK: call x86_thiscallcc %class.A* @"??0A@@QAE@XZ" |
| // CHECK: call i32 @atexit(void ()* @"??__Ffoo@?$B@H@@2VA@@A@YAXXZ") |
| // CHECK: ret void |
| |
| // CHECK: define linkonce_odr dso_local x86_thiscallcc %class.A* @"??0A@@QAE@XZ"({{.*}}) {{.*}} comdat |
| |
| // CHECK: define linkonce_odr dso_local x86_thiscallcc void @"??1A@@QAE@XZ"({{.*}}) {{.*}} comdat |
| |
| // CHECK: define internal void @"??__Ffoo@?$B@H@@2VA@@A@YAXXZ" |
| // CHECK: call x86_thiscallcc void @"??1A@@QAE@XZ"{{.*}}foo |
| // CHECK: ret void |
| |
| // CHECK: define internal void @_GLOBAL__sub_I_microsoft_abi_static_initializers.cpp() |
| // CHECK: call void @"??__Es@@YAXXZ"() |
| // CHECK: ret void |