| 1 | // RUN: %clang_cc1 -fms-extensions -fno-threadsafe-statics -emit-llvm %s -o - -mconstructor-aliases -triple=i386-pc-win32 | FileCheck %s |
| 2 | |
| 3 | // CHECK: @llvm.global_ctors = appending global [5 x { i32, void ()*, i8* }] [ |
| 4 | // CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"??__Eselectany1@@YAXXZ", i8* getelementptr inbounds (%struct.S, %struct.S* @"?selectany1@@3US@@A", i32 0, i32 0) }, |
| 5 | // CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"??__Eselectany2@@YAXXZ", i8* getelementptr inbounds (%struct.S, %struct.S* @"?selectany2@@3US@@A", i32 0, i32 0) }, |
| 6 | // 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) }, |
| 7 | // 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*) }, |
| 8 | // CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_microsoft_abi_static_initializers.cpp, i8* null } |
| 9 | // CHECK: ] |
| 10 | |
| 11 | struct S { |
| 12 | S(); |
| 13 | ~S(); |
| 14 | }; |
| 15 | |
| 16 | S s; |
| 17 | |
| 18 | // CHECK: define internal void @"??__Es@@YAXXZ"() |
| 19 | // CHECK: call x86_thiscallcc %struct.S* @"??0S@@QAE@XZ" |
| 20 | // CHECK: call i32 @atexit(void ()* @"??__Fs@@YAXXZ") |
| 21 | // CHECK: ret void |
| 22 | |
| 23 | // CHECK: define internal void @"??__Fs@@YAXXZ"() |
| 24 | // CHECK: call x86_thiscallcc void @"??1S@@QAE@XZ" |
| 25 | // CHECK: ret void |
| 26 | |
| 27 | // These globals should have initializers comdat associative with the global. |
| 28 | // See @llvm.global_ctors above. |
| 29 | __declspec(selectany) S selectany1; |
| 30 | __declspec(selectany) S selectany2; |
| 31 | // CHECK: define linkonce_odr dso_local void @"??__Eselectany1@@YAXXZ"() {{.*}} comdat |
| 32 | // CHECK-NOT: @"??_Bselectany1 |
| 33 | // CHECK: call x86_thiscallcc %struct.S* @"??0S@@QAE@XZ" |
| 34 | // CHECK: ret void |
| 35 | // CHECK: define linkonce_odr dso_local void @"??__Eselectany2@@YAXXZ"() {{.*}} comdat |
| 36 | // CHECK-NOT: @"??_Bselectany2 |
| 37 | // CHECK: call x86_thiscallcc %struct.S* @"??0S@@QAE@XZ" |
| 38 | // CHECK: ret void |
| 39 | |
| 40 | // The implicitly instantiated static data member should have initializer |
| 41 | // comdat associative with the global. |
| 42 | template <typename T> struct __declspec(dllexport) ExportedTemplate { |
| 43 | static S s; |
| 44 | }; |
| 45 | template <typename T> S ExportedTemplate<T>::s; |
| 46 | void useExportedTemplate(ExportedTemplate<int> x) { |
| 47 | (void)x.s; |
| 48 | } |
| 49 | |
| 50 | void StaticLocal() { |
| 51 | static S TheS; |
| 52 | } |
| 53 | |
| 54 | // CHECK-LABEL: define dso_local void @"?StaticLocal@@YAXXZ"() |
| 55 | // CHECK: load i32, i32* @"?$S1@?1??StaticLocal@@YAXXZ@4IA" |
| 56 | // CHECK: store i32 {{.*}}, i32* @"?$S1@?1??StaticLocal@@YAXXZ@4IA" |
| 57 | // CHECK: ret |
| 58 | |
| 59 | void MultipleStatics() { |
| 60 | static S S1; |
| 61 | static S S2; |
| 62 | static S S3; |
| 63 | static S S4; |
| 64 | static S S5; |
| 65 | static S S6; |
| 66 | static S S7; |
| 67 | static S S8; |
| 68 | static S S9; |
| 69 | static S S10; |
| 70 | static S S11; |
| 71 | static S S12; |
| 72 | static S S13; |
| 73 | static S S14; |
| 74 | static S S15; |
| 75 | static S S16; |
| 76 | static S S17; |
| 77 | static S S18; |
| 78 | static S S19; |
| 79 | static S S20; |
| 80 | static S S21; |
| 81 | static S S22; |
| 82 | static S S23; |
| 83 | static S S24; |
| 84 | static S S25; |
| 85 | static S S26; |
| 86 | static S S27; |
| 87 | static S S28; |
| 88 | static S S29; |
| 89 | static S S30; |
| 90 | static S S31; |
| 91 | static S S32; |
| 92 | static S S33; |
| 93 | static S S34; |
| 94 | static S S35; |
| 95 | } |
| 96 | // CHECK-LABEL: define dso_local void @"?MultipleStatics@@YAXXZ"() |
| 97 | // CHECK: load i32, i32* @"?$S1@?1??MultipleStatics@@YAXXZ@4IA" |
| 98 | // CHECK: and i32 {{.*}}, 1 |
| 99 | // CHECK: and i32 {{.*}}, 2 |
| 100 | // CHECK: and i32 {{.*}}, 4 |
| 101 | // CHECK: and i32 {{.*}}, 8 |
| 102 | // CHECK: and i32 {{.*}}, 16 |
| 103 | // ... |
| 104 | // CHECK: and i32 {{.*}}, -2147483648 |
| 105 | // CHECK: load i32, i32* @"?$S1@?1??MultipleStatics@@YAXXZ@4IA.1" |
| 106 | // CHECK: and i32 {{.*}}, 1 |
| 107 | // CHECK: and i32 {{.*}}, 2 |
| 108 | // CHECK: and i32 {{.*}}, 4 |
| 109 | // CHECK: ret |
| 110 | |
| 111 | // Force WeakODRLinkage by using templates |
| 112 | class A { |
| 113 | public: |
| 114 | A() {} |
| 115 | ~A() {} |
| 116 | int a; |
| 117 | }; |
| 118 | |
| 119 | template<typename T> |
| 120 | class B { |
| 121 | public: |
| 122 | static A foo; |
| 123 | }; |
| 124 | |
| 125 | template<typename T> A B<T>::foo; |
| 126 | |
| 127 | inline S &UnreachableStatic() { |
| 128 | if (0) { |
| 129 | static S s; // bit 1 |
| 130 | return s; |
| 131 | } |
| 132 | static S s; // bit 2 |
| 133 | return s; |
| 134 | } |
| 135 | |
| 136 | // CHECK-LABEL: define linkonce_odr dso_local dereferenceable({{[0-9]+}}) %struct.S* @"?UnreachableStatic@@YAAAUS@@XZ"() {{.*}} comdat |
| 137 | // CHECK: and i32 {{.*}}, 2 |
| 138 | // CHECK: or i32 {{.*}}, 2 |
| 139 | // CHECK: ret |
| 140 | |
| 141 | inline S &getS() { |
| 142 | static S TheS; |
| 143 | return TheS; |
| 144 | } |
| 145 | |
| 146 | // CHECK-LABEL: define linkonce_odr dso_local dereferenceable({{[0-9]+}}) %struct.S* @"?getS@@YAAAUS@@XZ"() {{.*}} comdat |
| 147 | // CHECK: load i32, i32* @"??_B?1??getS@@YAAAUS@@XZ@51" |
| 148 | // CHECK: and i32 {{.*}}, 1 |
| 149 | // CHECK: icmp eq i32 {{.*}}, 0 |
| 150 | // CHECK: br i1 |
| 151 | // init: |
| 152 | // CHECK: or i32 {{.*}}, 1 |
| 153 | // CHECK: store i32 {{.*}}, i32* @"??_B?1??getS@@YAAAUS@@XZ@51" |
| 154 | // CHECK: call x86_thiscallcc %struct.S* @"??0S@@QAE@XZ"(%struct.S* @"?TheS@?1??getS@@YAAAUS@@XZ@4U2@A") |
| 155 | // CHECK: call i32 @atexit(void ()* @"??__FTheS@?1??getS@@YAAAUS@@XZ@YAXXZ") |
| 156 | // CHECK: br label |
| 157 | // init.end: |
| 158 | // CHECK: ret %struct.S* @"?TheS@?1??getS@@YAAAUS@@XZ@4U2@A" |
| 159 | |
| 160 | inline int enum_in_function() { |
| 161 | // CHECK-LABEL: define linkonce_odr dso_local i32 @"?enum_in_function@@YAHXZ"() {{.*}} comdat |
| 162 | static enum e { foo, bar, baz } x; |
| 163 | // CHECK: @"?x@?1??enum_in_function@@YAHXZ@4W4e@?1??1@YAHXZ@A" |
| 164 | static int y; |
| 165 | // CHECK: @"?y@?1??enum_in_function@@YAHXZ@4HA" |
| 166 | return x + y; |
| 167 | }; |
| 168 | |
| 169 | struct T { |
| 170 | enum e { foo, bar, baz }; |
| 171 | int enum_in_struct() { |
| 172 | // CHECK-LABEL: define linkonce_odr dso_local x86_thiscallcc i32 @"?enum_in_struct@T@@QAEHXZ"({{.*}}) {{.*}} comdat |
| 173 | static int x; |
| 174 | // CHECK: @"?x@?1??enum_in_struct@T@@QAEHXZ@4HA" |
| 175 | return x++; |
| 176 | } |
| 177 | }; |
| 178 | |
| 179 | inline int switch_test(int x) { |
| 180 | // CHECK-LABEL: define linkonce_odr dso_local i32 @"?switch_test@@YAHH@Z"(i32 %x) {{.*}} comdat |
| 181 | switch (x) { |
| 182 | static int a; |
| 183 | // CHECK: @"?a@?3??switch_test@@YAHH@Z@4HA" |
| 184 | case 0: |
| 185 | a++; |
| 186 | return 1; |
| 187 | case 1: |
| 188 | static int b; |
| 189 | // CHECK: @"?b@?3??switch_test@@YAHH@Z@4HA" |
| 190 | return b++; |
| 191 | case 2: { |
| 192 | static int c; |
| 193 | // CHECK: @"?c@?4??switch_test@@YAHH@Z@4HA" |
| 194 | return b + c++; |
| 195 | } |
| 196 | }; |
| 197 | } |
| 198 | |
| 199 | int f(); |
| 200 | inline void switch_test2() { |
| 201 | // CHECK-LABEL: define linkonce_odr dso_local void @"?switch_test2@@YAXXZ"() {{.*}} comdat |
| 202 | // CHECK: @"?x@?2??switch_test2@@YAXXZ@4HA" |
| 203 | switch (1) default: static int x = f(); |
| 204 | } |
| 205 | |
| 206 | namespace DynamicDLLImportInitVSMangling { |
| 207 | // Failing to pop the ExprEvalContexts when instantiating a dllimport var with |
| 208 | // dynamic initializer would cause subsequent static local numberings to be |
| 209 | // incorrect. |
| 210 | struct NonPOD { NonPOD(); }; |
| 211 | template <typename T> struct A { static NonPOD x; }; |
| 212 | template <typename T> NonPOD A<T>::x; |
| 213 | template struct __declspec(dllimport) A<int>; |
| 214 | |
| 215 | inline int switch_test3() { |
| 216 | // CHECK-LABEL: define linkonce_odr dso_local i32 @"?switch_test3@DynamicDLLImportInitVSMangling@@YAHXZ"() {{.*}} comdat |
| 217 | static int local; |
| 218 | // CHECK: @"?local@?1??switch_test3@DynamicDLLImportInitVSMangling@@YAHXZ@4HA" |
| 219 | return local++; |
| 220 | } |
| 221 | } |
| 222 | |
| 223 | void force_usage() { |
| 224 | UnreachableStatic(); |
| 225 | getS(); |
| 226 | (void)B<int>::foo; // (void) - force usage |
| 227 | enum_in_function(); |
| 228 | (void)&T::enum_in_struct; |
| 229 | switch_test(1); |
| 230 | switch_test2(); |
| 231 | DynamicDLLImportInitVSMangling::switch_test3(); |
| 232 | } |
| 233 | |
| 234 | // CHECK: define linkonce_odr dso_local void @"??__E?foo@?$B@H@@2VA@@A@@YAXXZ"() {{.*}} comdat |
| 235 | // CHECK-NOT: and |
| 236 | // CHECK-NOT: ?_Bfoo@ |
| 237 | // CHECK: call x86_thiscallcc %class.A* @"??0A@@QAE@XZ" |
| 238 | // CHECK: call i32 @atexit(void ()* @"??__F?foo@?$B@H@@2VA@@A@@YAXXZ") |
| 239 | // CHECK: ret void |
| 240 | |
| 241 | // CHECK: define linkonce_odr dso_local x86_thiscallcc %class.A* @"??0A@@QAE@XZ"({{.*}}) {{.*}} comdat |
| 242 | |
| 243 | // CHECK: define linkonce_odr dso_local x86_thiscallcc void @"??1A@@QAE@XZ"({{.*}}) {{.*}} comdat |
| 244 | |
| 245 | // CHECK: define internal void @"??__F?foo@?$B@H@@2VA@@A@@YAXXZ" |
| 246 | // CHECK: call x86_thiscallcc void @"??1A@@QAE@XZ"{{.*}}foo |
| 247 | // CHECK: ret void |
| 248 | |
| 249 | // CHECK: define internal void @_GLOBAL__sub_I_microsoft_abi_static_initializers.cpp() |
| 250 | // CHECK: call void @"??__Es@@YAXXZ"() |
| 251 | // CHECK: ret void |
| 252 | |