xref: /minix3/external/bsd/llvm/dist/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp (revision 0b98e8aad89f2bd4ba80b523d73cf29e9dd82ce1)
1 // RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-linux | FileCheck -check-prefix LINUX %s
2 // RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -cxx-abi microsoft -fno-rtti | FileCheck -check-prefix WIN32 %s
3 // RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-pc-win32 -mconstructor-aliases -cxx-abi microsoft -fno-rtti | FileCheck -check-prefix WIN64 %s
4 
5 struct Empty {};
6 
7 struct EmptyWithCtor {
8   EmptyWithCtor() {}
9 };
10 
11 struct Small {
12   int x;
13 };
14 
15 // This is a C++11 trivial and standard-layout struct but not a C++03 POD.
16 struct SmallCpp11NotCpp03Pod : Empty {
17   int x;
18 };
19 
20 struct SmallWithCtor {
21   SmallWithCtor() {}
22   int x;
23 };
24 
25 struct SmallWithDtor {
26   SmallWithDtor();
27   ~SmallWithDtor();
28   int x;
29 };
30 
31 struct SmallWithVftable {
32   int x;
33   virtual void foo();
34 };
35 
36 struct Medium {
37   int x, y;
38 };
39 
40 struct MediumWithCopyCtor {
41   MediumWithCopyCtor();
42   MediumWithCopyCtor(const struct MediumWithCopyCtor &);
43   int x, y;
44 };
45 
46 struct Big {
47   int a, b, c, d, e, f;
48 };
49 
50 // Returning structs that fit into a register.
51 Small small_return() { return Small(); }
52 // LINUX-LABEL: define void @_Z12small_returnv(%struct.Small* noalias sret %agg.result)
53 // WIN32: define i32 @"\01?small_return@@YA?AUSmall@@XZ"()
54 // WIN64: define i32 @"\01?small_return@@YA?AUSmall@@XZ"()
55 
56 Medium medium_return() { return Medium(); }
57 // LINUX-LABEL: define void @_Z13medium_returnv(%struct.Medium* noalias sret %agg.result)
58 // WIN32: define i64 @"\01?medium_return@@YA?AUMedium@@XZ"()
59 // WIN64: define i64 @"\01?medium_return@@YA?AUMedium@@XZ"()
60 
61 // Returning structs that fit into a register but are not POD.
62 SmallCpp11NotCpp03Pod small_non_pod_return() { return SmallCpp11NotCpp03Pod(); }
63 // LINUX-LABEL: define void @_Z20small_non_pod_returnv(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result)
64 // WIN32: define void @"\01?small_non_pod_return@@YA?AUSmallCpp11NotCpp03Pod@@XZ"(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result)
65 // WIN64: define void @"\01?small_non_pod_return@@YA?AUSmallCpp11NotCpp03Pod@@XZ"(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result)
66 
67 SmallWithCtor small_with_ctor_return() { return SmallWithCtor(); }
68 // LINUX-LABEL: define void @_Z22small_with_ctor_returnv(%struct.SmallWithCtor* noalias sret %agg.result)
69 // WIN32: define void @"\01?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret %agg.result)
70 // WIN64: define void @"\01?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret %agg.result)
71 
72 SmallWithVftable small_with_vftable_return() { return SmallWithVftable(); }
73 // LINUX-LABEL: define void @_Z25small_with_vftable_returnv(%struct.SmallWithVftable* noalias sret %agg.result)
74 // WIN32: define void @"\01?small_with_vftable_return@@YA?AUSmallWithVftable@@XZ"(%struct.SmallWithVftable* noalias sret %agg.result)
75 // WIN64: define void @"\01?small_with_vftable_return@@YA?AUSmallWithVftable@@XZ"(%struct.SmallWithVftable* noalias sret %agg.result)
76 
77 MediumWithCopyCtor medium_with_copy_ctor_return() { return MediumWithCopyCtor(); }
78 // LINUX-LABEL: define void @_Z28medium_with_copy_ctor_returnv(%struct.MediumWithCopyCtor* noalias sret %agg.result)
79 // WIN32: define void @"\01?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret %agg.result)
80 // WIN64: define void @"\01?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret %agg.result)
81 
82 // Returning a large struct that doesn't fit into a register.
83 Big big_return() { return Big(); }
84 // LINUX-LABEL: define void @_Z10big_returnv(%struct.Big* noalias sret %agg.result)
85 // WIN32: define void @"\01?big_return@@YA?AUBig@@XZ"(%struct.Big* noalias sret %agg.result)
86 // WIN64: define void @"\01?big_return@@YA?AUBig@@XZ"(%struct.Big* noalias sret %agg.result)
87 
88 
89 void small_arg(Small s) {}
90 // LINUX-LABEL: define void @_Z9small_arg5Small(%struct.Small* byval align 4 %s)
91 // WIN32: define void @"\01?small_arg@@YAXUSmall@@@Z"(%struct.Small* byval align 4 %s)
92 // WIN64: define void @"\01?small_arg@@YAXUSmall@@@Z"(i32 %s.coerce)
93 
94 void medium_arg(Medium s) {}
95 // LINUX-LABEL: define void @_Z10medium_arg6Medium(%struct.Medium* byval align 4 %s)
96 // WIN32: define void @"\01?medium_arg@@YAXUMedium@@@Z"(%struct.Medium* byval align 4 %s)
97 // WIN64: define void @"\01?medium_arg@@YAXUMedium@@@Z"(i64 %s.coerce)
98 
99 void small_arg_with_ctor(SmallWithCtor s) {}
100 // LINUX-LABEL: define void @_Z19small_arg_with_ctor13SmallWithCtor(%struct.SmallWithCtor* byval align 4 %s)
101 // WIN32: define void @"\01?small_arg_with_ctor@@YAXUSmallWithCtor@@@Z"(%struct.SmallWithCtor* byval align 4 %s)
102 // WIN64: define void @"\01?small_arg_with_ctor@@YAXUSmallWithCtor@@@Z"(i32 %s.coerce)
103 
104 // Test that dtors are invoked in the callee.
105 void small_arg_with_dtor(SmallWithDtor s) {}
106 // WIN32: define void @"\01?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(%struct.SmallWithDtor* byval align 4 %s) {{.*}} {
107 // WIN32:   call x86_thiscallcc void @"\01??1SmallWithDtor@@QAE@XZ"(%struct.SmallWithDtor* %s)
108 // WIN32: }
109 // WIN64: define void @"\01?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(%struct.SmallWithDtor* byval %s) {{.*}} {
110 // WIN64:   call void @"\01??1SmallWithDtor@@QEAA@XZ"(%struct.SmallWithDtor* %s)
111 // WIN64: }
112 
113 // Test that references aren't destroyed in the callee.
114 void ref_small_arg_with_dtor(const SmallWithDtor &s) { }
115 // WIN32: define void @"\01?ref_small_arg_with_dtor@@YAXABUSmallWithDtor@@@Z"(%struct.SmallWithDtor* %s) {{.*}} {
116 // WIN32-NOT:   call x86_thiscallcc void @"\01??1SmallWithDtor@@QAE@XZ"
117 // WIN32: }
118 
119 // Test that temporaries passed by reference are destroyed in the caller.
120 void temporary_ref_with_dtor() {
121   ref_small_arg_with_dtor(SmallWithDtor());
122 }
123 // WIN32: define void @"\01?temporary_ref_with_dtor@@YAXXZ"() {{.*}} {
124 // WIN32:   call x86_thiscallcc %struct.SmallWithDtor* @"\01??0SmallWithDtor@@QAE@XZ"
125 // WIN32:   call void @"\01?ref_small_arg_with_dtor@@YAXABUSmallWithDtor@@@Z"
126 // WIN32:   call x86_thiscallcc void @"\01??1SmallWithDtor@@QAE@XZ"
127 // WIN32: }
128 
129 void takes_two_by_val_with_dtor(SmallWithDtor a, SmallWithDtor b);
130 void eh_cleanup_arg_with_dtor() {
131   takes_two_by_val_with_dtor(SmallWithDtor(), SmallWithDtor());
132 }
133 //   When exceptions are off, we don't have any cleanups.  See
134 //   microsoft-abi-exceptions.cpp for these cleanups.
135 // WIN32: define void @"\01?eh_cleanup_arg_with_dtor@@YAXXZ"() {{.*}} {
136 // WIN32:   call x86_thiscallcc %struct.SmallWithDtor* @"\01??0SmallWithDtor@@QAE@XZ"
137 // WIN32:   call x86_thiscallcc %struct.SmallWithDtor* @"\01??0SmallWithDtor@@QAE@XZ"
138 // WIN32:   call void @"\01?takes_two_by_val_with_dtor@@YAXUSmallWithDtor@@0@Z"
139 // WIN32-NOT: call x86_thiscallcc void @"\01??1SmallWithDtor@@QAE@XZ"
140 // WIN32: }
141 
142 void small_arg_with_vftable(SmallWithVftable s) {}
143 // LINUX-LABEL: define void @_Z22small_arg_with_vftable16SmallWithVftable(%struct.SmallWithVftable* %s)
144 // WIN32: define void @"\01?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(%struct.SmallWithVftable* byval align 4 %s)
145 // WIN64: define void @"\01?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(%struct.SmallWithVftable* byval %s)
146 
147 void medium_arg_with_copy_ctor(MediumWithCopyCtor s) {}
148 // LINUX-LABEL: define void @_Z25medium_arg_with_copy_ctor18MediumWithCopyCtor(%struct.MediumWithCopyCtor* %s)
149 // WIN32: define void @"\01?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(%struct.MediumWithCopyCtor* byval align 4 %s)
150 // WIN64: define void @"\01?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(%struct.MediumWithCopyCtor* byval %s)
151 
152 void big_arg(Big s) {}
153 // LINUX-LABEL: define void @_Z7big_arg3Big(%struct.Big* byval align 4 %s)
154 // WIN32: define void @"\01?big_arg@@YAXUBig@@@Z"(%struct.Big* byval align 4 %s)
155 // WIN64: define void @"\01?big_arg@@YAXUBig@@@Z"(%struct.Big* %s)
156 
157 // FIXME: Add WIN64 tests. Currently, even the method manglings are wrong (sic!).
158 class Class {
159  public:
160   Small thiscall_method_small() { return Small(); }
161   // LINUX: define {{.*}} void @_ZN5Class21thiscall_method_smallEv(%struct.Small* noalias sret %agg.result, %class.Class* %this)
162   // WIN32: define {{.*}} x86_thiscallcc void @"\01?thiscall_method_small@Class@@QAE?AUSmall@@XZ"(%struct.Small* noalias sret %agg.result, %class.Class* %this)
163 
164   SmallWithCtor thiscall_method_small_with_ctor() { return SmallWithCtor(); }
165   // LINUX: define {{.*}} void @_ZN5Class31thiscall_method_small_with_ctorEv(%struct.SmallWithCtor* noalias sret %agg.result, %class.Class* %this)
166   // WIN32: define {{.*}} x86_thiscallcc void @"\01?thiscall_method_small_with_ctor@Class@@QAE?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret %agg.result, %class.Class* %this)
167 
168   Small __cdecl cdecl_method_small() { return Small(); }
169   // LINUX: define {{.*}} void @_ZN5Class18cdecl_method_smallEv(%struct.Small* noalias sret %agg.result, %class.Class* %this)
170   // FIXME: Interesting, cdecl returns structures differently for instance
171   // methods and global functions. This is not supported by Clang yet...
172   // FIXME: Replace WIN32-NOT with WIN32 when this is fixed.
173   // WIN32-NOT: define {{.*}} void @"\01?cdecl_method_small@Class@@QAA?AUSmall@@XZ"(%struct.Small* noalias sret %agg.result, %class.Class* %this)
174 
175   Big __cdecl cdecl_method_big() { return Big(); }
176   // LINUX: define {{.*}} void @_ZN5Class16cdecl_method_bigEv(%struct.Big* noalias sret %agg.result, %class.Class* %this)
177   // WIN32: define {{.*}} void @"\01?cdecl_method_big@Class@@QAA?AUBig@@XZ"(%struct.Big* noalias sret %agg.result, %class.Class* %this)
178 
179   void thiscall_method_arg(Empty s) {}
180   // LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE5Empty(%class.Class* %this)
181   // WIN32: define {{.*}} void @"\01?thiscall_method_arg@Class@@QAEXUEmpty@@@Z"(%class.Class* %this, %struct.Empty* byval align 4 %s)
182 
183   void thiscall_method_arg(EmptyWithCtor s) {}
184   // LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE13EmptyWithCtor(%class.Class* %this)
185   // WIN32: define {{.*}} void @"\01?thiscall_method_arg@Class@@QAEXUEmptyWithCtor@@@Z"(%class.Class* %this, %struct.EmptyWithCtor* byval align 4 %s)
186 
187   void thiscall_method_arg(Small s) {}
188   // LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE5Small(%class.Class* %this, %struct.Small* byval align 4 %s)
189   // WIN32: define {{.*}} void @"\01?thiscall_method_arg@Class@@QAEXUSmall@@@Z"(%class.Class* %this, %struct.Small* byval align 4 %s)
190 
191   void thiscall_method_arg(SmallWithCtor s) {}
192   // LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE13SmallWithCtor(%class.Class* %this, %struct.SmallWithCtor* byval align 4 %s)
193   // WIN32: define {{.*}} void @"\01?thiscall_method_arg@Class@@QAEXUSmallWithCtor@@@Z"(%class.Class* %this, %struct.SmallWithCtor* byval align 4 %s)
194 
195   void thiscall_method_arg(Big s) {}
196   // LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE3Big(%class.Class* %this, %struct.Big* byval align 4 %s)
197   // WIN32: define {{.*}} void @"\01?thiscall_method_arg@Class@@QAEXUBig@@@Z"(%class.Class* %this, %struct.Big* byval align 4 %s)
198 };
199 
200 void use_class() {
201   Class c;
202   c.thiscall_method_small();
203   c.thiscall_method_small_with_ctor();
204 
205   c.cdecl_method_small();
206   c.cdecl_method_big();
207 
208   c.thiscall_method_arg(Empty());
209   c.thiscall_method_arg(EmptyWithCtor());
210   c.thiscall_method_arg(Small());
211   c.thiscall_method_arg(SmallWithCtor());
212   c.thiscall_method_arg(Big());
213 }
214 
215 struct X {
216   X();
217   ~X();
218 };
219 void g(X) {
220 }
221 // WIN32: define void @"\01?g@@YAXUX@@@Z"(%struct.X* byval align 4) {{.*}} {
222 // WIN32:   call x86_thiscallcc void @"\01??1X@@QAE@XZ"(%struct.X* %0)
223 // WIN32: }
224 void f() {
225   g(X());
226 }
227 // WIN32: define void @"\01?f@@YAXXZ"() {{.*}} {
228 // WIN32-NOT: call {{.*}} @"\01??1X@@QAE@XZ"
229 // WIN32: }
230