xref: /llvm-project/clang/test/CodeGenCXX/trivial_abi.cpp (revision 94473f4db6a6f5f12d7c4081455b5b596094eac5)
1 // RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fcxx-exceptions -fexceptions -emit-llvm -o - %s | FileCheck %s
2 // RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fcxx-exceptions -fexceptions -fclang-abi-compat=4.0 -emit-llvm -o - %s | FileCheck %s
3 
4 // CHECK: %[[STRUCT_SMALL:.*]] = type { ptr }
5 // CHECK: %[[STRUCT_LARGE:.*]] = type { ptr, [128 x i32] }
6 // CHECK: %[[STRUCT_TRIVIAL:.*]] = type { i32 }
7 // CHECK: %[[STRUCT_NONTRIVIAL:.*]] = type { i32 }
8 
9 struct __attribute__((trivial_abi)) Small {
10   int *p;
11   Small();
12   ~Small();
13   Small(const Small &) noexcept;
14   Small &operator=(const Small &);
15 };
16 
17 struct __attribute__((trivial_abi)) Large {
18   int *p;
19   int a[128];
20   Large();
21   ~Large();
22   Large(const Large &) noexcept;
23   Large &operator=(const Large &);
24 };
25 
26 struct Trivial {
27   int a;
28 };
29 
30 struct NonTrivial {
31   NonTrivial();
32   ~NonTrivial();
33   int a;
34 };
35 
36 struct HasTrivial {
37   Small s;
38   Trivial m;
39 };
40 
41 struct HasNonTrivial {
42   Small s;
43   NonTrivial m;
44 };
45 
46 struct B0 {
47   virtual Small m0();
48 };
49 
50 struct B1 {
51   virtual Small m0();
52 };
53 
54 struct D0 : B0, B1 {
55   Small m0() override;
56 };
57 
58 // CHECK-LABEL: define{{.*}} i64 @_ZThn8_N2D02m0Ev(
59 // CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_SMALL]], align 8
60 // CHECK: %[[CALL:.*]] = tail call i64 @_ZN2D02m0Ev(
61 // CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds nuw %[[STRUCT_SMALL]], ptr %[[RETVAL]], i32 0, i32 0
62 // CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[CALL]] to ptr
63 // CHECK: store ptr %[[COERCE_VAL_IP]], ptr %[[COERCE_DIVE]], align 8
64 // CHECK: %[[COERCE_DIVE2:.*]] = getelementptr inbounds nuw %[[STRUCT_SMALL]], ptr %[[RETVAL]], i32 0, i32 0
65 // CHECK: %[[V3:.*]] = load ptr, ptr %[[COERCE_DIVE2]], align 8
66 // CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint ptr %[[V3]] to i64
67 // CHECK: ret i64 %[[COERCE_VAL_PI]]
68 
69 Small D0::m0() { return {}; }
70 
71 // CHECK: define{{.*}} void @_Z14testParamSmall5Small(i64 %[[A_COERCE:.*]])
72 // CHECK: %[[A:.*]] = alloca %[[STRUCT_SMALL]], align 8
73 // CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds nuw %[[STRUCT_SMALL]], ptr %[[A]], i32 0, i32 0
74 // CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[A_COERCE]] to ptr
75 // CHECK: store ptr %[[COERCE_VAL_IP]], ptr %[[COERCE_DIVE]], align 8
76 // CHECK: %[[CALL:.*]] = call noundef ptr @_ZN5SmallD1Ev(ptr {{[^,]*}} %[[A]])
77 // CHECK: ret void
78 // CHECK: }
79 
80 void testParamSmall(Small a) noexcept {
81 }
82 
83 // CHECK: define{{.*}} i64 @_Z15testReturnSmallv()
84 // CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_SMALL:.*]], align 8
85 // CHECK: %[[CALL:.*]] = call noundef ptr @_ZN5SmallC1Ev(ptr {{[^,]*}} %[[RETVAL]])
86 // CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds nuw %[[STRUCT_SMALL]], ptr %[[RETVAL]], i32 0, i32 0
87 // CHECK: %[[V0:.*]] = load ptr, ptr %[[COERCE_DIVE]], align 8
88 // CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint ptr %[[V0]] to i64
89 // CHECK: ret i64 %[[COERCE_VAL_PI]]
90 // CHECK: }
91 
92 Small testReturnSmall() {
93   Small t;
94   return t;
95 }
96 
97 // CHECK: define{{.*}} void @_Z14testCallSmall0v()
98 // CHECK: %[[T:.*]] = alloca %[[STRUCT_SMALL:.*]], align 8
99 // CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_SMALL]], align 8
100 // CHECK: %[[CALL:.*]] = call noundef ptr @_ZN5SmallC1Ev(ptr {{[^,]*}} %[[T]])
101 // CHECK: %[[CALL1:.*]] = call noundef ptr @_ZN5SmallC1ERKS_(ptr {{[^,]*}} %[[AGG_TMP]], ptr noundef nonnull align 8 dereferenceable(8) %[[T]])
102 // CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds nuw %[[STRUCT_SMALL]], ptr %[[AGG_TMP]], i32 0, i32 0
103 // CHECK: %[[V0:.*]] = load ptr, ptr %[[COERCE_DIVE]], align 8
104 // CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint ptr %[[V0]] to i64
105 // CHECK: call void @_Z14testParamSmall5Small(i64 %[[COERCE_VAL_PI]])
106 // CHECK: %[[CALL2:.*]] = call noundef ptr @_ZN5SmallD1Ev(ptr {{[^,]*}} %[[T]])
107 // CHECK: ret void
108 // CHECK: }
109 
110 void testCallSmall0() {
111   Small t;
112   testParamSmall(t);
113 }
114 
115 // CHECK: define{{.*}} void @_Z14testCallSmall1v()
116 // CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_SMALL:.*]], align 8
117 // CHECK: %[[CALL:.*]] = call i64 @_Z15testReturnSmallv()
118 // CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds nuw %[[STRUCT_SMALL]], ptr %[[AGG_TMP]], i32 0, i32 0
119 // CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[CALL]] to ptr
120 // CHECK: store ptr %[[COERCE_VAL_IP]], ptr %[[COERCE_DIVE]], align 8
121 // CHECK: %[[COERCE_DIVE1:.*]] = getelementptr inbounds nuw %[[STRUCT_SMALL]], ptr %[[AGG_TMP]], i32 0, i32 0
122 // CHECK: %[[V0:.*]] = load ptr, ptr %[[COERCE_DIVE1]], align 8
123 // CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint ptr %[[V0]] to i64
124 // CHECK: call void @_Z14testParamSmall5Small(i64 %[[COERCE_VAL_PI]])
125 // CHECK: ret void
126 // CHECK: }
127 
128 void testCallSmall1() {
129   testParamSmall(testReturnSmall());
130 }
131 
132 // CHECK: define{{.*}} void @_Z16testIgnoredSmallv()
133 // CHECK: %[[AGG_TMP_ENSURED:.*]] = alloca %[[STRUCT_SMALL:.*]], align 8
134 // CHECK: %[[CALL:.*]] = call i64 @_Z15testReturnSmallv()
135 // CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds nuw %[[STRUCT_SMALL]], ptr %[[AGG_TMP_ENSURED]], i32 0, i32 0
136 // CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[CALL]] to ptr
137 // CHECK: store ptr %[[COERCE_VAL_IP]], ptr %[[COERCE_DIVE]], align 8
138 // CHECK: %[[CALL1:.*]] = call noundef ptr @_ZN5SmallD1Ev(ptr {{[^,]*}} %[[AGG_TMP_ENSURED]])
139 // CHECK: ret void
140 // CHECK: }
141 
142 void testIgnoredSmall() {
143   testReturnSmall();
144 }
145 
146 // CHECK: define{{.*}} void @_Z14testParamLarge5Large(ptr noundef %[[A:.*]])
147 // CHECK: %[[CALL:.*]] = call noundef ptr @_ZN5LargeD1Ev(ptr {{[^,]*}} %[[A]])
148 // CHECK: ret void
149 // CHECK: }
150 
151 void testParamLarge(Large a) noexcept {
152 }
153 
154 // CHECK: define{{.*}} void @_Z15testReturnLargev(ptr dead_on_unwind noalias writable sret(%[[STRUCT_LARGE]]) align 8 %[[AGG_RESULT:.*]])
155 // CHECK: %[[CALL:.*]] = call noundef ptr @_ZN5LargeC1Ev(ptr {{[^,]*}} %[[AGG_RESULT]])
156 // CHECK: ret void
157 // CHECK: }
158 
159 Large testReturnLarge() {
160   Large t;
161   return t;
162 }
163 
164 // CHECK: define{{.*}} void @_Z14testCallLarge0v()
165 // CHECK: %[[T:.*]] = alloca %[[STRUCT_LARGE:.*]], align 8
166 // CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_LARGE]], align 8
167 // CHECK: %[[CALL:.*]] = call noundef ptr @_ZN5LargeC1Ev(ptr {{[^,]*}} %[[T]])
168 // CHECK: %[[CALL1:.*]] = call noundef ptr @_ZN5LargeC1ERKS_(ptr {{[^,]*}} %[[AGG_TMP]], ptr noundef nonnull align 8 dereferenceable(520) %[[T]])
169 // CHECK: call void @_Z14testParamLarge5Large(ptr noundef %[[AGG_TMP]])
170 // CHECK: %[[CALL2:.*]] = call noundef ptr @_ZN5LargeD1Ev(ptr {{[^,]*}} %[[T]])
171 // CHECK: ret void
172 // CHECK: }
173 
174 void testCallLarge0() {
175   Large t;
176   testParamLarge(t);
177 }
178 
179 // CHECK: define{{.*}} void @_Z14testCallLarge1v()
180 // CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_LARGE:.*]], align 8
181 // CHECK: call void @_Z15testReturnLargev(ptr dead_on_unwind writable sret(%[[STRUCT_LARGE]]) align 8 %[[AGG_TMP]])
182 // CHECK: call void @_Z14testParamLarge5Large(ptr noundef %[[AGG_TMP]])
183 // CHECK: ret void
184 // CHECK: }
185 
186 void testCallLarge1() {
187   testParamLarge(testReturnLarge());
188 }
189 
190 // CHECK: define{{.*}} void @_Z16testIgnoredLargev()
191 // CHECK: %[[AGG_TMP_ENSURED:.*]] = alloca %[[STRUCT_LARGE:.*]], align 8
192 // CHECK: call void @_Z15testReturnLargev(ptr dead_on_unwind writable sret(%[[STRUCT_LARGE]]) align 8 %[[AGG_TMP_ENSURED]])
193 // CHECK: %[[CALL:.*]] = call noundef ptr @_ZN5LargeD1Ev(ptr {{[^,]*}} %[[AGG_TMP_ENSURED]])
194 // CHECK: ret void
195 // CHECK: }
196 
197 void testIgnoredLarge() {
198   testReturnLarge();
199 }
200 
201 // CHECK: define{{.*}} i32 @_Z20testReturnHasTrivialv()
202 // CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_TRIVIAL:.*]], align 4
203 // CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds nuw %[[STRUCT_TRIVIAL]], ptr %[[RETVAL]], i32 0, i32 0
204 // CHECK: %[[V0:.*]] = load i32, ptr %[[COERCE_DIVE]], align 4
205 // CHECK: ret i32 %[[V0]]
206 // CHECK: }
207 
208 Trivial testReturnHasTrivial() {
209   Trivial t;
210   return t;
211 }
212 
213 // CHECK: define{{.*}} void @_Z23testReturnHasNonTrivialv(ptr dead_on_unwind noalias writable sret(%[[STRUCT_NONTRIVIAL:.*]]) align 4 %[[AGG_RESULT:.*]])
214 // CHECK: %[[CALL:.*]] = call noundef ptr @_ZN10NonTrivialC1Ev(ptr {{[^,]*}} %[[AGG_RESULT]])
215 // CHECK: ret void
216 // CHECK: }
217 
218 NonTrivial testReturnHasNonTrivial() {
219   NonTrivial t;
220   return t;
221 }
222 
223 // CHECK: define{{.*}} void @_Z18testExceptionSmallv()
224 // CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_SMALL]], align 8
225 // CHECK: %[[AGG_TMP1:.*]] = alloca %[[STRUCT_SMALL]], align 8
226 // CHECK: call noundef ptr @_ZN5SmallC1Ev(ptr {{[^,]*}} %[[AGG_TMP]])
227 // CHECK: invoke noundef ptr @_ZN5SmallC1Ev(ptr {{[^,]*}} %[[AGG_TMP1]])
228 
229 // CHECK: call void @_Z20calleeExceptionSmall5SmallS_(i64 %{{.*}}, i64 %{{.*}})
230 // CHECK-NEXT: ret void
231 
232 // CHECK: landingpad { ptr, i32 }
233 // CHECK: call noundef ptr @_ZN5SmallD1Ev(ptr {{[^,]*}} %[[AGG_TMP]])
234 // CHECK: br
235 
236 // CHECK: resume { ptr, i32 }
237 
238 void calleeExceptionSmall(Small, Small);
239 
240 void testExceptionSmall() {
241   calleeExceptionSmall(Small(), Small());
242 }
243 
244 // CHECK: define{{.*}} void @_Z18testExceptionLargev()
245 // CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_LARGE]], align 8
246 // CHECK: %[[AGG_TMP1:.*]] = alloca %[[STRUCT_LARGE]], align 8
247 // CHECK: call noundef ptr @_ZN5LargeC1Ev(ptr {{[^,]*}} %[[AGG_TMP]])
248 // CHECK: invoke noundef ptr @_ZN5LargeC1Ev(ptr {{[^,]*}} %[[AGG_TMP1]])
249 
250 // CHECK: call void @_Z20calleeExceptionLarge5LargeS_(ptr noundef %[[AGG_TMP]], ptr noundef %[[AGG_TMP1]])
251 // CHECK-NEXT: ret void
252 
253 // CHECK: landingpad { ptr, i32 }
254 // CHECK: call noundef ptr @_ZN5LargeD1Ev(ptr {{[^,]*}} %[[AGG_TMP]])
255 // CHECK: br
256 
257 // CHECK: resume { ptr, i32 }
258 
259 void calleeExceptionLarge(Large, Large);
260 
261 void testExceptionLarge() {
262   calleeExceptionLarge(Large(), Large());
263 }
264 
265 // CHECK: define void @_ZN7GH930401gEPNS_1SE
266 // CHECK: [[CALL:%.*]] = call i64 @_ZN7GH930401fEv
267 // CHECK-NEXT: [[TRUNC:%.*]] = trunc i64 [[CALL]] to i56
268 // CHECK-NEXT: store i56 [[TRUNC]]
269 // CHECK-NEXT: ret void
270 void* operator new(unsigned long, void*);
271 namespace GH93040 {
272 struct [[clang::trivial_abi]] S {
273   char a;
274   int x;
275   __attribute((aligned(2))) char y;
276   S();
277 } __attribute((packed));
278 S f();
279 void g(S* s) { new(s) S(f()); }
280 struct S2 { [[no_unique_address]] S s; char c;};
281 static_assert(sizeof(S) == 8 && sizeof(S2) == 8, "");
282 }
283 
284 
285 // PR42961
286 
287 // CHECK: define{{.*}} @"_ZN3$_08__invokeEv"()
288 // CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_SMALL]], align 8
289 // CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_SMALL]], align 8
290 // CHECK: %[[CALL:.*]] = call{{.*}} @"_ZNK3$_0clEv"
291 // CHECK: %[[COERCEDIVE:.*]] = getelementptr{{.*}} %[[COERCE]]
292 // CHECK: %[[COERCEVALIP:.*]] = inttoptr{{.*}} %[[CALL]]
293 // CHECK: call {{.*}}memcpy{{.*}} %[[RETVAL]]{{.*}} %[[COERCE]]
294 // CHECK: %[[COERCEDIVE1:.*]] = getelementptr{{.*}} %[[RETVAL]]
295 // CHECK: %[[TMP:.*]] = load{{.*}} %[[COERCEDIVE1]]
296 // CHECK: %[[COERCEVALPI:.*]] = ptrtoint{{.*}} %[[TMP]]
297 // CHECK: ret{{.*}} %[[COERCEVALPI]]
298 
299 Small (*fp)() = []() -> Small { return Small(); };
300