1 | // RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple=i386-pc-linux | FileCheck -check-prefix LINUX %s |
2 | // RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fno-rtti | FileCheck -check-prefix WIN32 %s |
3 | // RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple=thumb-pc-win32 -mconstructor-aliases -fno-rtti | FileCheck -check-prefix WOA %s |
4 | // RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple=x86_64-pc-win32 -mconstructor-aliases -fno-rtti | FileCheck -check-prefix WIN64 %s |
5 | // RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple=aarch64-windows-msvc -mconstructor-aliases -fno-rtti | FileCheck -check-prefix WOA64 %s |
6 | |
7 | struct Empty {}; |
8 | |
9 | struct EmptyWithCtor { |
10 | EmptyWithCtor() {} |
11 | }; |
12 | |
13 | struct Small { |
14 | int x; |
15 | }; |
16 | |
17 | // This is a C++11 trivial and standard-layout struct but not a C++03 POD. |
18 | struct SmallCpp11NotCpp03Pod : Empty { |
19 | int x; |
20 | }; |
21 | |
22 | struct SmallWithCtor { |
23 | SmallWithCtor() {} |
24 | int x; |
25 | }; |
26 | |
27 | struct Multibyte { |
28 | char a, b, c, d; |
29 | }; |
30 | |
31 | struct Packed { |
32 | short a; |
33 | int b; |
34 | short c; |
35 | }; |
36 | |
37 | struct SmallWithDtor { |
38 | SmallWithDtor(); |
39 | ~SmallWithDtor(); |
40 | int x; |
41 | }; |
42 | |
43 | struct SmallWithVftable { |
44 | int x; |
45 | virtual void foo(); |
46 | }; |
47 | |
48 | struct Medium { |
49 | int x, y; |
50 | }; |
51 | |
52 | struct MediumWithCopyCtor { |
53 | MediumWithCopyCtor(); |
54 | MediumWithCopyCtor(const struct MediumWithCopyCtor &); |
55 | int x, y; |
56 | }; |
57 | |
58 | struct Big { |
59 | int a, b, c, d, e, f; |
60 | }; |
61 | |
62 | struct BigWithDtor { |
63 | BigWithDtor(); |
64 | ~BigWithDtor(); |
65 | int a, b, c, d, e, f; |
66 | }; |
67 | |
68 | struct BaseNoByval : Small { |
69 | int bb; |
70 | }; |
71 | |
72 | // WIN32: declare dso_local void @"{{.*take_bools_and_chars.*}}" |
73 | // WIN32: (<{ i8, [3 x i8], i8, [3 x i8], %struct.SmallWithDtor, |
74 | // WIN32: i8, [3 x i8], i8, [3 x i8], i32, i8, [3 x i8] }>* inalloca) |
75 | void take_bools_and_chars(char a, char b, SmallWithDtor c, char d, bool e, int f, bool g); |
76 | void call_bools_and_chars() { |
77 | take_bools_and_chars('A', 'B', SmallWithDtor(), 'D', true, 13, false); |
78 | } |
79 | |
80 | // Returning structs that fit into a register. |
81 | Small small_return() { return Small(); } |
82 | // LINUX-LABEL: define void @_Z12small_returnv(%struct.Small* noalias sret %agg.result) |
83 | // WIN32: define dso_local i32 @"?small_return@@YA?AUSmall@@XZ"() |
84 | // WIN64: define dso_local i32 @"?small_return@@YA?AUSmall@@XZ"() |
85 | |
86 | Medium medium_return() { return Medium(); } |
87 | // LINUX-LABEL: define void @_Z13medium_returnv(%struct.Medium* noalias sret %agg.result) |
88 | // WIN32: define dso_local i64 @"?medium_return@@YA?AUMedium@@XZ"() |
89 | // WIN64: define dso_local i64 @"?medium_return@@YA?AUMedium@@XZ"() |
90 | |
91 | // Returning structs that fit into a register but are not POD. |
92 | SmallCpp11NotCpp03Pod small_non_pod_return() { return SmallCpp11NotCpp03Pod(); } |
93 | // LINUX-LABEL: define void @_Z20small_non_pod_returnv(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result) |
94 | // WIN32: define dso_local void @"?small_non_pod_return@@YA?AUSmallCpp11NotCpp03Pod@@XZ"(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result) |
95 | // WIN64: define dso_local void @"?small_non_pod_return@@YA?AUSmallCpp11NotCpp03Pod@@XZ"(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result) |
96 | |
97 | SmallWithCtor small_with_ctor_return() { return SmallWithCtor(); } |
98 | // LINUX-LABEL: define void @_Z22small_with_ctor_returnv(%struct.SmallWithCtor* noalias sret %agg.result) |
99 | // WIN32: define dso_local void @"?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret %agg.result) |
100 | // WIN64: define dso_local void @"?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret %agg.result) |
101 | // FIXME: The 'sret' mark here doesn't seem to be enough to convince LLVM to |
102 | // preserve the hidden sret pointer in R0 across the function. |
103 | // WOA: define dso_local arm_aapcs_vfpcc void @"?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret %agg.result) |
104 | |
105 | SmallWithVftable small_with_vftable_return() { return SmallWithVftable(); } |
106 | // LINUX-LABEL: define void @_Z25small_with_vftable_returnv(%struct.SmallWithVftable* noalias sret %agg.result) |
107 | // WIN32: define dso_local void @"?small_with_vftable_return@@YA?AUSmallWithVftable@@XZ"(%struct.SmallWithVftable* noalias sret %agg.result) |
108 | // WIN64: define dso_local void @"?small_with_vftable_return@@YA?AUSmallWithVftable@@XZ"(%struct.SmallWithVftable* noalias sret %agg.result) |
109 | |
110 | MediumWithCopyCtor medium_with_copy_ctor_return() { return MediumWithCopyCtor(); } |
111 | // LINUX-LABEL: define void @_Z28medium_with_copy_ctor_returnv(%struct.MediumWithCopyCtor* noalias sret %agg.result) |
112 | // WIN32: define dso_local void @"?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret %agg.result) |
113 | // WIN64: define dso_local void @"?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret %agg.result) |
114 | // WOA: define dso_local arm_aapcs_vfpcc void @"?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret %agg.result) |
115 | |
116 | // Returning a large struct that doesn't fit into a register. |
117 | Big big_return() { return Big(); } |
118 | // LINUX-LABEL: define void @_Z10big_returnv(%struct.Big* noalias sret %agg.result) |
119 | // WIN32: define dso_local void @"?big_return@@YA?AUBig@@XZ"(%struct.Big* noalias sret %agg.result) |
120 | // WIN64: define dso_local void @"?big_return@@YA?AUBig@@XZ"(%struct.Big* noalias sret %agg.result) |
121 | |
122 | |
123 | void small_arg(Small s) {} |
124 | // LINUX-LABEL: define void @_Z9small_arg5Small(i32 %s.0) |
125 | // WIN32: define dso_local void @"?small_arg@@YAXUSmall@@@Z"(i32 %s.0) |
126 | // WIN64: define dso_local void @"?small_arg@@YAXUSmall@@@Z"(i32 %s.coerce) |
127 | // WOA: define dso_local arm_aapcs_vfpcc void @"?small_arg@@YAXUSmall@@@Z"([1 x i32] %s.coerce) |
128 | |
129 | void medium_arg(Medium s) {} |
130 | // LINUX-LABEL: define void @_Z10medium_arg6Medium(i32 %s.0, i32 %s.1) |
131 | // WIN32: define dso_local void @"?medium_arg@@YAXUMedium@@@Z"(i32 %s.0, i32 %s.1) |
132 | // WIN64: define dso_local void @"?medium_arg@@YAXUMedium@@@Z"(i64 %s.coerce) |
133 | // WOA: define dso_local arm_aapcs_vfpcc void @"?medium_arg@@YAXUMedium@@@Z"([2 x i32] %s.coerce) |
134 | |
135 | void base_no_byval_arg(BaseNoByval s) {} |
136 | // LINUX-LABEL: define void @_Z17base_no_byval_arg11BaseNoByval(%struct.BaseNoByval* byval align 4 %s) |
137 | // WIN32: define dso_local void @"?base_no_byval_arg@@YAXUBaseNoByval@@@Z"(i32 %s.0, i32 %s.1) |
138 | // WIN64: define dso_local void @"?base_no_byval_arg@@YAXUBaseNoByval@@@Z"(i64 %s.coerce) |
139 | // WOA: define dso_local arm_aapcs_vfpcc void @"?base_no_byval_arg@@YAXUBaseNoByval@@@Z"([2 x i32] %s.coerce) |
140 | |
141 | void small_arg_with_ctor(SmallWithCtor s) {} |
142 | // LINUX-LABEL: define void @_Z19small_arg_with_ctor13SmallWithCtor(%struct.SmallWithCtor* byval align 4 %s) |
143 | // WIN32: define dso_local void @"?small_arg_with_ctor@@YAXUSmallWithCtor@@@Z"(i32 %s.0) |
144 | // WIN64: define dso_local void @"?small_arg_with_ctor@@YAXUSmallWithCtor@@@Z"(i32 %s.coerce) |
145 | // WOA: define dso_local arm_aapcs_vfpcc void @"?small_arg_with_ctor@@YAXUSmallWithCtor@@@Z"([1 x i32] %s.coerce) |
146 | |
147 | // FIXME: We could coerce to a series of i32s here if we wanted to. |
148 | void multibyte_arg(Multibyte s) {} |
149 | // LINUX-LABEL: define void @_Z13multibyte_arg9Multibyte(%struct.Multibyte* byval align 4 %s) |
150 | // WIN32: define dso_local void @"?multibyte_arg@@YAXUMultibyte@@@Z"(%struct.Multibyte* byval align 4 %s) |
151 | // WIN64: define dso_local void @"?multibyte_arg@@YAXUMultibyte@@@Z"(i32 %s.coerce) |
152 | // WOA: define dso_local arm_aapcs_vfpcc void @"?multibyte_arg@@YAXUMultibyte@@@Z"([1 x i32] %s.coerce) |
153 | |
154 | void packed_arg(Packed s) {} |
155 | // LINUX-LABEL: define void @_Z10packed_arg6Packed(%struct.Packed* byval align 4 %s) |
156 | // WIN32: define dso_local void @"?packed_arg@@YAXUPacked@@@Z"(%struct.Packed* byval align 4 %s) |
157 | // WIN64: define dso_local void @"?packed_arg@@YAXUPacked@@@Z"(%struct.Packed* %s) |
158 | |
159 | // Test that dtors are invoked in the callee. |
160 | void small_arg_with_dtor(SmallWithDtor s) {} |
161 | // WIN32: define dso_local void @"?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(<{ %struct.SmallWithDtor }>* inalloca) {{.*}} { |
162 | // WIN32: call x86_thiscallcc void @"??1SmallWithDtor@@QAE@XZ" |
163 | // WIN32: } |
164 | // WIN64: define dso_local void @"?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(i32 %s.coerce) {{.*}} { |
165 | // WIN64: call void @"??1SmallWithDtor@@QEAA@XZ" |
166 | // WIN64: } |
167 | // WOA64: define dso_local void @"?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(i64 %s.coerce) {{.*}} { |
168 | // WOA64: call void @"??1SmallWithDtor@@QEAA@XZ" |
169 | // WOA64: } |
170 | |
171 | // FIXME: MSVC incompatible! |
172 | // WOA: define dso_local arm_aapcs_vfpcc void @"?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(%struct.SmallWithDtor* %s) {{.*}} { |
173 | // WOA: call arm_aapcs_vfpcc void @"??1SmallWithDtor@@QAA@XZ"(%struct.SmallWithDtor* %s) |
174 | // WOA: } |
175 | |
176 | void call_small_arg_with_dtor() { |
177 | small_arg_with_dtor(SmallWithDtor()); |
178 | } |
179 | // WIN64-LABEL: define dso_local void @"?call_small_arg_with_dtor@@YAXXZ"() |
180 | // WIN64: call %struct.SmallWithDtor* @"??0SmallWithDtor@@QEAA@XZ" |
181 | // WIN64: call void @"?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(i32 %{{.*}}) |
182 | // WIN64: ret void |
183 | |
184 | // Test that references aren't destroyed in the callee. |
185 | void ref_small_arg_with_dtor(const SmallWithDtor &s) { } |
186 | // WIN32: define dso_local void @"?ref_small_arg_with_dtor@@YAXABUSmallWithDtor@@@Z"(%struct.SmallWithDtor* dereferenceable({{[0-9]+}}) %s) {{.*}} { |
187 | // WIN32-NOT: call x86_thiscallcc void @"??1SmallWithDtor@@QAE@XZ" |
188 | // WIN32: } |
189 | // WIN64-LABEL: define dso_local void @"?ref_small_arg_with_dtor@@YAXAEBUSmallWithDtor@@@Z"(%struct.SmallWithDtor* dereferenceable({{[0-9]+}}) %s) |
190 | |
191 | void big_arg_with_dtor(BigWithDtor s) {} |
192 | // WIN64-LABEL: define dso_local void @"?big_arg_with_dtor@@YAXUBigWithDtor@@@Z"(%struct.BigWithDtor* %s) |
193 | // WIN64: call void @"??1BigWithDtor@@QEAA@XZ" |
194 | // WIN64: } |
195 | |
196 | void call_big_arg_with_dtor() { |
197 | big_arg_with_dtor(BigWithDtor()); |
198 | } |
199 | // We can elide the copy of the temporary in the caller, because this object is |
200 | // larger than 8 bytes and is passed indirectly. |
201 | // WIN64-LABEL: define dso_local void @"?call_big_arg_with_dtor@@YAXXZ"() |
202 | // WIN64: call %struct.BigWithDtor* @"??0BigWithDtor@@QEAA@XZ" |
203 | // WIN64: call void @"?big_arg_with_dtor@@YAXUBigWithDtor@@@Z"(%struct.BigWithDtor* %{{.*}}) |
204 | // WIN64-NOT: call void @"??1BigWithDtor@@QEAA@XZ" |
205 | // WIN64: ret void |
206 | |
207 | // Test that temporaries passed by reference are destroyed in the caller. |
208 | void temporary_ref_with_dtor() { |
209 | ref_small_arg_with_dtor(SmallWithDtor()); |
210 | } |
211 | // WIN32: define dso_local void @"?temporary_ref_with_dtor@@YAXXZ"() {{.*}} { |
212 | // WIN32: call x86_thiscallcc %struct.SmallWithDtor* @"??0SmallWithDtor@@QAE@XZ" |
213 | // WIN32: call void @"?ref_small_arg_with_dtor@@YAXABUSmallWithDtor@@@Z" |
214 | // WIN32: call x86_thiscallcc void @"??1SmallWithDtor@@QAE@XZ" |
215 | // WIN32: } |
216 | |
217 | void takes_two_by_val_with_dtor(SmallWithDtor a, SmallWithDtor b); |
218 | void eh_cleanup_arg_with_dtor() { |
219 | takes_two_by_val_with_dtor(SmallWithDtor(), SmallWithDtor()); |
220 | } |
221 | // When exceptions are off, we don't have any cleanups. See |
222 | // microsoft-abi-exceptions.cpp for these cleanups. |
223 | // WIN32: define dso_local void @"?eh_cleanup_arg_with_dtor@@YAXXZ"() {{.*}} { |
224 | // WIN32: call x86_thiscallcc %struct.SmallWithDtor* @"??0SmallWithDtor@@QAE@XZ" |
225 | // WIN32: call x86_thiscallcc %struct.SmallWithDtor* @"??0SmallWithDtor@@QAE@XZ" |
226 | // WIN32: call void @"?takes_two_by_val_with_dtor@@YAXUSmallWithDtor@@0@Z" |
227 | // WIN32-NOT: call x86_thiscallcc void @"??1SmallWithDtor@@QAE@XZ" |
228 | // WIN32: } |
229 | |
230 | void small_arg_with_vftable(SmallWithVftable s) {} |
231 | // LINUX-LABEL: define void @_Z22small_arg_with_vftable16SmallWithVftable(%struct.SmallWithVftable* %s) |
232 | // WIN32: define dso_local void @"?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(<{ %struct.SmallWithVftable }>* inalloca) |
233 | // WIN64: define dso_local void @"?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(%struct.SmallWithVftable* %s) |
234 | // WOA64: define dso_local void @"?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(%struct.SmallWithVftable* %s) |
235 | |
236 | void medium_arg_with_copy_ctor(MediumWithCopyCtor s) {} |
237 | // LINUX-LABEL: define void @_Z25medium_arg_with_copy_ctor18MediumWithCopyCtor(%struct.MediumWithCopyCtor* %s) |
238 | // WIN32: define dso_local void @"?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(<{ %struct.MediumWithCopyCtor }>* inalloca) |
239 | // WIN64: define dso_local void @"?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(%struct.MediumWithCopyCtor* %s) |
240 | // WOA: define dso_local arm_aapcs_vfpcc void @"?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(%struct.MediumWithCopyCtor* %s) |
241 | // WOA64: define dso_local void @"?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(%struct.MediumWithCopyCtor* %s) |
242 | |
243 | void big_arg(Big s) {} |
244 | // LINUX-LABEL: define void @_Z7big_arg3Big(%struct.Big* byval align 4 %s) |
245 | // WIN32: define dso_local void @"?big_arg@@YAXUBig@@@Z"(%struct.Big* byval align 4 %s) |
246 | // WIN64: define dso_local void @"?big_arg@@YAXUBig@@@Z"(%struct.Big* %s) |
247 | |
248 | // PR27607: We would attempt to load i32 value out of the reference instead of |
249 | // just loading the pointer from the struct during argument expansion. |
250 | struct RefField { |
251 | RefField(int &x); |
252 | int &x; |
253 | }; |
254 | void takes_ref_field(RefField s) {} |
255 | // LINUX-LABEL: define void @_Z15takes_ref_field8RefField(%struct.RefField* byval align 4 %s) |
256 | // WIN32: define dso_local void @"?takes_ref_field@@YAXURefField@@@Z"(i32* %s.0) |
257 | // WIN64: define dso_local void @"?takes_ref_field@@YAXURefField@@@Z"(i64 %s.coerce) |
258 | |
259 | void pass_ref_field() { |
260 | int x; |
261 | takes_ref_field(RefField(x)); |
262 | } |
263 | // LINUX-LABEL: define void @_Z14pass_ref_fieldv() |
264 | // LINUX: call void @_Z15takes_ref_field8RefField(%struct.RefField* byval align 4 %{{.*}}) |
265 | // WIN32-LABEL: define dso_local void @"?pass_ref_field@@YAXXZ"() |
266 | // WIN32: call void @"?takes_ref_field@@YAXURefField@@@Z"(i32* %{{.*}}) |
267 | // WIN64-LABEL: define dso_local void @"?pass_ref_field@@YAXXZ"() |
268 | // WIN64: call void @"?takes_ref_field@@YAXURefField@@@Z"(i64 %{{.*}}) |
269 | |
270 | class Class { |
271 | public: |
272 | Small thiscall_method_small() { return Small(); } |
273 | // LINUX: define {{.*}} void @_ZN5Class21thiscall_method_smallEv(%struct.Small* noalias sret %agg.result, %class.Class* %this) |
274 | // WIN32: define {{.*}} x86_thiscallcc void @"?thiscall_method_small@Class@@QAE?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret %agg.result) |
275 | // WIN64: define linkonce_odr dso_local void @"?thiscall_method_small@Class@@QEAA?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret %agg.result) |
276 | |
277 | SmallWithCtor thiscall_method_small_with_ctor() { return SmallWithCtor(); } |
278 | // LINUX: define {{.*}} void @_ZN5Class31thiscall_method_small_with_ctorEv(%struct.SmallWithCtor* noalias sret %agg.result, %class.Class* %this) |
279 | // WIN32: define {{.*}} x86_thiscallcc void @"?thiscall_method_small_with_ctor@Class@@QAE?AUSmallWithCtor@@XZ"(%class.Class* %this, %struct.SmallWithCtor* noalias sret %agg.result) |
280 | // WIN64: define linkonce_odr dso_local void @"?thiscall_method_small_with_ctor@Class@@QEAA?AUSmallWithCtor@@XZ"(%class.Class* %this, %struct.SmallWithCtor* noalias sret %agg.result) |
281 | |
282 | Small __cdecl cdecl_method_small() { return Small(); } |
283 | // LINUX: define {{.*}} void @_ZN5Class18cdecl_method_smallEv(%struct.Small* noalias sret %agg.result, %class.Class* %this) |
284 | // WIN32: define {{.*}} void @"?cdecl_method_small@Class@@QAA?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret %agg.result) |
285 | // WIN64: define linkonce_odr dso_local void @"?cdecl_method_small@Class@@QEAA?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret %agg.result) |
286 | |
287 | Big __cdecl cdecl_method_big() { return Big(); } |
288 | // LINUX: define {{.*}} void @_ZN5Class16cdecl_method_bigEv(%struct.Big* noalias sret %agg.result, %class.Class* %this) |
289 | // WIN32: define {{.*}} void @"?cdecl_method_big@Class@@QAA?AUBig@@XZ"(%class.Class* %this, %struct.Big* noalias sret %agg.result) |
290 | // WIN64: define linkonce_odr dso_local void @"?cdecl_method_big@Class@@QEAA?AUBig@@XZ"(%class.Class* %this, %struct.Big* noalias sret %agg.result) |
291 | |
292 | void thiscall_method_arg(Empty s) {} |
293 | // LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE5Empty(%class.Class* %this) |
294 | // WIN32: define {{.*}} void @"?thiscall_method_arg@Class@@QAEXUEmpty@@@Z"(%class.Class* %this, %struct.Empty* byval align 4 %s) |
295 | // WIN64: define linkonce_odr dso_local void @"?thiscall_method_arg@Class@@QEAAXUEmpty@@@Z"(%class.Class* %this, i8 %s.coerce) |
296 | |
297 | void thiscall_method_arg(EmptyWithCtor s) {} |
298 | // LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE13EmptyWithCtor(%class.Class* %this) |
299 | // WIN32: define {{.*}} void @"?thiscall_method_arg@Class@@QAEXUEmptyWithCtor@@@Z"(%class.Class* %this, %struct.EmptyWithCtor* byval align 4 %s) |
300 | // WIN64: define linkonce_odr dso_local void @"?thiscall_method_arg@Class@@QEAAXUEmptyWithCtor@@@Z"(%class.Class* %this, i8 %s.coerce) |
301 | |
302 | void thiscall_method_arg(Small s) {} |
303 | // LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE5Small(%class.Class* %this, i32 %s.0) |
304 | // WIN32: define {{.*}} void @"?thiscall_method_arg@Class@@QAEXUSmall@@@Z"(%class.Class* %this, i32 %s.0) |
305 | // WIN64: define linkonce_odr dso_local void @"?thiscall_method_arg@Class@@QEAAXUSmall@@@Z"(%class.Class* %this, i32 %s.coerce) |
306 | |
307 | void thiscall_method_arg(SmallWithCtor s) {} |
308 | // LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE13SmallWithCtor(%class.Class* %this, %struct.SmallWithCtor* byval align 4 %s) |
309 | // WIN32: define {{.*}} void @"?thiscall_method_arg@Class@@QAEXUSmallWithCtor@@@Z"(%class.Class* %this, i32 %s.0) |
310 | // WIN64: define linkonce_odr dso_local void @"?thiscall_method_arg@Class@@QEAAXUSmallWithCtor@@@Z"(%class.Class* %this, i32 %s.coerce) |
311 | |
312 | void thiscall_method_arg(Big s) {} |
313 | // LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE3Big(%class.Class* %this, %struct.Big* byval align 4 %s) |
314 | // WIN32: define {{.*}} void @"?thiscall_method_arg@Class@@QAEXUBig@@@Z"(%class.Class* %this, %struct.Big* byval align 4 %s) |
315 | // WIN64: define linkonce_odr dso_local void @"?thiscall_method_arg@Class@@QEAAXUBig@@@Z"(%class.Class* %this, %struct.Big* %s) |
316 | }; |
317 | |
318 | void use_class() { |
319 | Class c; |
320 | c.thiscall_method_small(); |
321 | c.thiscall_method_small_with_ctor(); |
322 | |
323 | c.cdecl_method_small(); |
324 | c.cdecl_method_big(); |
325 | |
326 | c.thiscall_method_arg(Empty()); |
327 | c.thiscall_method_arg(EmptyWithCtor()); |
328 | c.thiscall_method_arg(Small()); |
329 | c.thiscall_method_arg(SmallWithCtor()); |
330 | c.thiscall_method_arg(Big()); |
331 | } |
332 | |
333 | struct X { |
334 | X(); |
335 | ~X(); |
336 | }; |
337 | void g(X) { |
338 | } |
339 | // WIN32: define dso_local void @"?g@@YAXUX@@@Z"(<{ %struct.X, [3 x i8] }>* inalloca) {{.*}} { |
340 | // WIN32: call x86_thiscallcc void @"??1X@@QAE@XZ"(%struct.X* {{.*}}) |
341 | // WIN32: } |
342 | void f() { |
343 | g(X()); |
344 | } |
345 | // WIN32: define dso_local void @"?f@@YAXXZ"() {{.*}} { |
346 | // WIN32-NOT: call {{.*}} @"??1X@@QAE@XZ" |
347 | // WIN32: } |
348 | |
349 | |
350 | namespace test2 { |
351 | // We used to crash on this due to the mixture of POD byval and non-trivial |
352 | // byval. |
353 | |
354 | struct NonTrivial { |
355 | NonTrivial(); |
356 | NonTrivial(const NonTrivial &o); |
357 | ~NonTrivial(); |
358 | int a; |
359 | }; |
360 | struct POD { int b; }; |
361 | |
362 | int foo(NonTrivial a, POD b); |
363 | void bar() { |
364 | POD b; |
365 | b.b = 13; |
366 | int c = foo(NonTrivial(), b); |
367 | } |
368 | // WIN32-LABEL: define dso_local void @"?bar@test2@@YAXXZ"() {{.*}} { |
369 | // WIN32: %[[argmem:[^ ]*]] = alloca inalloca [[argmem_ty:<{ %"struct.test2::NonTrivial", %"struct.test2::POD" }>]] |
370 | // WIN32: getelementptr inbounds [[argmem_ty]], [[argmem_ty]]* %[[argmem]], i32 0, i32 1 |
371 | // WIN32: call void @llvm.memcpy |
372 | // WIN32: getelementptr inbounds [[argmem_ty]], [[argmem_ty]]* %[[argmem]], i32 0, i32 0 |
373 | // WIN32: call x86_thiscallcc %"struct.test2::NonTrivial"* @"??0NonTrivial@test2@@QAE@XZ" |
374 | // WIN32: call i32 @"?foo@test2@@YAHUNonTrivial@1@UPOD@1@@Z"([[argmem_ty]]* inalloca %argmem) |
375 | // WIN32: ret void |
376 | // WIN32: } |
377 | |
378 | } |
379 | |
380 | namespace test3 { |
381 | |
382 | // Check that we padded the inalloca struct to a multiple of 4. |
383 | struct NonTrivial { |
384 | NonTrivial(); |
385 | NonTrivial(const NonTrivial &o); |
386 | ~NonTrivial(); |
387 | int a; |
388 | }; |
389 | void foo(NonTrivial a, bool b) { } |
390 | // WIN32-LABEL: define dso_local void @"?foo@test3@@YAXUNonTrivial@1@_N@Z"(<{ %"struct.test3::NonTrivial", i8, [3 x i8] }>* inalloca) |
391 | |
392 | } |
393 | |
394 | // We would crash here because the later definition of ForwardDeclare1 results |
395 | // in a different IR type for the value we want to store. However, the alloca's |
396 | // type will use the argument type selected by fn1. |
397 | struct ForwardDeclare1; |
398 | |
399 | typedef void (*FnPtr1)(ForwardDeclare1); |
400 | void fn1(FnPtr1 a, SmallWithDtor b) { } |
401 | |
402 | struct ForwardDeclare1 {}; |
403 | |
404 | void fn2(FnPtr1 a, SmallWithDtor b) { fn1(a, b); }; |
405 | // WIN32-LABEL: define dso_local void @"?fn2@@YAXP6AXUForwardDeclare1@@@ZUSmallWithDtor@@@Z" |
406 | // WIN32: %[[a:[^ ]*]] = getelementptr inbounds [[argmem_ty:<{ {}\*, %struct.SmallWithDtor }>]], [[argmem_ty:<{ {}\*, %struct.SmallWithDtor }>]]* %{{.*}}, i32 0, i32 0 |
407 | // WIN32: %[[a1:[^ ]*]] = bitcast {}** %[[a]] to void [[dst_ty:\(%struct.ForwardDeclare1\*\)\*]]* |
408 | // WIN32: %[[argmem:[^ ]*]] = alloca inalloca [[argmem_ty]] |
409 | // WIN32: %[[gep1:[^ ]*]] = getelementptr inbounds [[argmem_ty]], [[argmem_ty]]* %[[argmem]], i32 0, i32 1 |
410 | // WIN32: %[[bc1:[^ ]*]] = bitcast %struct.SmallWithDtor* %[[gep1]] to i8* |
411 | // WIN32: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %[[bc1]], i8* align 4 {{.*}}, i32 4, i1 false) |
412 | // WIN32: %[[a2:[^ ]*]] = load void [[dst_ty]], void [[dst_ty]]* %[[a1]], align 4 |
413 | // WIN32: %[[gep2:[^ ]*]] = getelementptr inbounds [[argmem_ty]], [[argmem_ty]]* %[[argmem]], i32 0, i32 0 |
414 | // WIN32: %[[addr:[^ ]*]] = bitcast {}** %[[gep2]] to void [[dst_ty]]* |
415 | // WIN32: store void [[dst_ty]] %[[a2]], void [[dst_ty]]* %[[addr]], align 4 |
416 | // WIN32: call void @"?fn1@@YAXP6AXUForwardDeclare1@@@ZUSmallWithDtor@@@Z"([[argmem_ty]]* inalloca %[[argmem]]) |
417 | |
418 | namespace pr30293 { |
419 | // Virtual methods living in a secondary vtable take i8* as their 'this' |
420 | // parameter because the 'this' parameter on entry points to the secondary |
421 | // vptr. We used to have a bug where we didn't apply this rule consistently, |
422 | // and it would cause assertion failures when used with inalloca. |
423 | struct A { |
424 | virtual void f(); |
425 | }; |
426 | struct B { |
427 | virtual void __cdecl h(SmallWithDtor); |
428 | }; |
429 | struct C final : A, B { |
430 | void g(); |
431 | void __cdecl h(SmallWithDtor); |
432 | void f(); |
433 | }; |
434 | void C::g() { return h(SmallWithDtor()); } |
435 | |
436 | // WIN32-LABEL: define dso_local x86_thiscallcc void @"?g@C@pr30293@@QAEXXZ"(%"struct.pr30293::C"* %this) |
437 | // WIN32: call x86_thiscallcc %struct.SmallWithDtor* @"??0SmallWithDtor@@QAE@XZ" |
438 | // WIN32: call void @"?h@C@pr30293@@UAAXUSmallWithDtor@@@Z"(<{ i8*, %struct.SmallWithDtor }>* inalloca %{{[^,)]*}}) |
439 | // WIN32: declare dso_local void @"?h@C@pr30293@@UAAXUSmallWithDtor@@@Z"(<{ i8*, %struct.SmallWithDtor }>* inalloca) |
440 | |
441 | // WIN64-LABEL: define dso_local void @"?g@C@pr30293@@QEAAXXZ"(%"struct.pr30293::C"* %this) |
442 | // WIN64: declare dso_local void @"?h@C@pr30293@@UEAAXUSmallWithDtor@@@Z"(i8*, i32) |
443 | } |
444 | |