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 | |