xref: /llvm-project/clang/test/CodeGenObjCXX/objc-struct-cxx-abi.mm (revision 94473f4db6a6f5f12d7c4081455b5b596094eac5)
1// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc  -fobjc-weak -fobjc-runtime-has-weak -emit-llvm -o - %s | FileCheck %s
2// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc  -fobjc-weak -fobjc-runtime-has-weak -fclang-abi-compat=4.0 -emit-llvm -o - %s | FileCheck %s
3// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc  -fobjc-weak -fobjc-runtime-has-weak -emit-llvm -o - -DTRIVIALABI %s | FileCheck %s
4// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc  -fobjc-weak -fobjc-runtime-has-weak -fclang-abi-compat=4.0 -emit-llvm -o - -DTRIVIALABI %s | FileCheck %s
5
6// Check that structs consisting solely of __strong or __weak pointer fields are
7// destructed in the callee function and structs consisting solely of __strong
8// pointer fields are passed directly.
9
10// CHECK: %[[STRUCT_STRONGWEAK:.*]] = type { ptr, ptr }
11// CHECK: %[[STRUCT_STRONG:.*]] = type { ptr }
12// CHECK: %[[STRUCT_CONTAINSNONTRIVIAL:.*]] = type { %{{.*}}, ptr }
13// CHECK: %[[STRUCT_NONTRIVIAL:.*]] = type { ptr }
14// CHECK: %[[STRUCT_CONTAINSSTRONGWEAK:.*]] = type { %[[STRUCT_STRONGWEAK]] }
15// CHECK: %[[STRUCT_S:.*]] = type { ptr }
16
17#ifdef TRIVIALABI
18struct __attribute__((trivial_abi)) StrongWeak {
19#else
20struct StrongWeak {
21#endif
22  id fstrong;
23  __weak id fweak;
24};
25
26#ifdef TRIVIALABI
27struct __attribute__((trivial_abi)) ContainsStrongWeak {
28#else
29struct ContainsStrongWeak {
30#endif
31  StrongWeak sw;
32};
33
34#ifdef TRIVIALABI
35struct __attribute__((trivial_abi)) DerivedStrongWeak : StrongWeak {
36#else
37struct DerivedStrongWeak : StrongWeak {
38#endif
39};
40
41#ifdef TRIVIALABI
42struct __attribute__((trivial_abi)) Strong {
43#else
44struct Strong {
45#endif
46  id fstrong;
47};
48
49template<class T>
50#ifdef TRIVIALABI
51struct __attribute__((trivial_abi)) S {
52#else
53struct S {
54#endif
55  T a;
56};
57
58struct NonTrivial {
59  NonTrivial();
60  NonTrivial(const NonTrivial &);
61  ~NonTrivial();
62  int *a;
63};
64
65// This struct is not passed directly nor destructed in the callee because f0
66// has type NonTrivial.
67struct ContainsNonTrivial {
68  NonTrivial f0;
69  id f1;
70};
71
72@interface C
73- (void)passStrong:(Strong)a;
74- (void)passStrongWeak:(StrongWeak)a;
75- (void)passNonTrivial:(NonTrivial)a;
76@end
77
78// CHECK: define{{.*}} void @_Z19testParamStrongWeak10StrongWeak(ptr noundef %{{.*}})
79// CHECK: call noundef ptr @_ZN10StrongWeakD1Ev(
80// CHECK-NEXT: ret void
81
82void testParamStrongWeak(StrongWeak a) {
83}
84
85// CHECK: define{{.*}} void @_Z18testCallStrongWeakP10StrongWeak(ptr noundef %[[A:.*]])
86// CHECK: %[[A_ADDR:.*]] = alloca ptr, align 8
87// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONGWEAK]], align 8
88// CHECK: store ptr %[[A]], ptr %[[A_ADDR]], align 8
89// CHECK: %[[V0:.*]] = load ptr, ptr %[[A_ADDR]], align 8
90// CHECK: %[[CALL:.*]] = call noundef ptr @_ZN10StrongWeakC1ERKS_(ptr {{[^,]*}} %[[AGG_TMP]], ptr noundef nonnull align 8 dereferenceable(16) %[[V0]])
91// CHECK: call void @_Z19testParamStrongWeak10StrongWeak(ptr noundef %[[AGG_TMP]])
92// CHECK-NOT: call
93// CHECK: ret void
94
95void testCallStrongWeak(StrongWeak *a) {
96  testParamStrongWeak(*a);
97}
98
99// CHECK: define{{.*}} void @_Z20testReturnStrongWeakP10StrongWeak(ptr dead_on_unwind noalias writable sret(%[[STRUCT_STRONGWEAK:.*]]) align 8 %[[AGG_RESULT:.*]], ptr noundef %[[A:.*]])
100// CHECK: %[[A_ADDR:a.addr]] = alloca ptr, align 8
101// CHECK: store ptr %[[A]], ptr %[[A_ADDR]], align 8
102// CHECK: %[[V0:.*]] = load ptr, ptr %[[A_ADDR]], align 8
103// CHECK: %[[CALL:.*]] = call noundef ptr @_ZN10StrongWeakC1ERKS_(ptr {{[^,]*}} %[[AGG_RESULT]], ptr noundef nonnull align 8 dereferenceable(16) %[[V0]])
104// CHECK: ret void
105
106StrongWeak testReturnStrongWeak(StrongWeak *a) {
107  return *a;
108}
109
110// CHECK: define{{.*}} void @_Z27testParamContainsStrongWeak18ContainsStrongWeak(ptr noundef %[[A:.*]])
111// CHECK: call noundef ptr @_ZN18ContainsStrongWeakD1Ev(ptr {{[^,]*}} %[[A]])
112
113void testParamContainsStrongWeak(ContainsStrongWeak a) {
114}
115
116// CHECK: define{{.*}} void @_Z26testParamDerivedStrongWeak17DerivedStrongWeak(ptr noundef %[[A:.*]])
117// CHECK: call noundef ptr @_ZN17DerivedStrongWeakD1Ev(ptr {{[^,]*}} %[[A]])
118
119void testParamDerivedStrongWeak(DerivedStrongWeak a) {
120}
121
122// CHECK: define{{.*}} void @_Z15testParamStrong6Strong(i64 %[[A_COERCE:.*]])
123// CHECK: %[[A:.*]] = alloca %[[STRUCT_STRONG]], align 8
124// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds nuw %[[STRUCT_STRONG]], ptr %[[A]], i32 0, i32 0
125// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[A_COERCE]] to ptr
126// CHECK: store ptr %[[COERCE_VAL_IP]], ptr %[[COERCE_DIVE]], align 8
127// CHECK: %[[CALL:.*]] = call noundef ptr @_ZN6StrongD1Ev(ptr {{[^,]*}} %[[A]])
128// CHECK: ret void
129
130// CHECK: define linkonce_odr noundef ptr @_ZN6StrongD1Ev(
131
132void testParamStrong(Strong a) {
133}
134
135// CHECK: define{{.*}} void @_Z14testCallStrongP6Strong(ptr noundef %[[A:.*]])
136// CHECK: %[[A_ADDR:.*]] = alloca ptr, align 8
137// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONG]], align 8
138// CHECK: store ptr %[[A]], ptr %[[A_ADDR]], align 8
139// CHECK: %[[V0:.*]] = load ptr, ptr %[[A_ADDR]], align 8
140// CHECK: %[[CALL:.*]] = call noundef ptr @_ZN6StrongC1ERKS_(ptr {{[^,]*}} %[[AGG_TMP]], ptr noundef nonnull align 8 dereferenceable(8) %[[V0]])
141// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds nuw %[[STRUCT_STRONG]], ptr %[[AGG_TMP]], i32 0, i32 0
142// CHECK: %[[V1:.*]] = load ptr, ptr %[[COERCE_DIVE]], align 8
143// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint ptr %[[V1]] to i64
144// CHECK: call void @_Z15testParamStrong6Strong(i64 %[[COERCE_VAL_PI]])
145// CHECK: ret void
146
147void testCallStrong(Strong *a) {
148  testParamStrong(*a);
149}
150
151// CHECK: define{{.*}} i64 @_Z16testReturnStrongP6Strong(ptr noundef %[[A:.*]])
152// CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_STRONG]], align 8
153// CHECK: %[[A_ADDR:.*]] = alloca ptr, align 8
154// CHECK: store ptr %[[A]], ptr %[[A_ADDR]], align 8
155// CHECK: %[[V0:.*]] = load ptr, ptr %[[A_ADDR]], align 8
156// CHECK: %[[CALL:.*]] = call noundef ptr @_ZN6StrongC1ERKS_(ptr {{[^,]*}} %[[RETVAL]], ptr noundef nonnull align 8 dereferenceable(8) %[[V0]])
157// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds nuw %[[STRUCT_STRONG]], ptr %[[RETVAL]], i32 0, i32 0
158// CHECK: %[[V1:.*]] = load ptr, ptr %[[COERCE_DIVE]], align 8
159// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint ptr %[[V1]] to i64
160// CHECK: ret i64 %[[COERCE_VAL_PI]]
161
162Strong testReturnStrong(Strong *a) {
163  return *a;
164}
165
166// CHECK: define{{.*}} void @_Z21testParamWeakTemplate1SIU6__weakP11objc_objectE(ptr noundef %{{.*}})
167// CHECK: call noundef ptr @_ZN1SIU6__weakP11objc_objectED1Ev(
168// CHECK-NEXT: ret void
169
170void testParamWeakTemplate(S<__weak id> a) {
171}
172
173// CHECK: define{{.*}} void @_Z27testParamContainsNonTrivial18ContainsNonTrivial(ptr noundef %{{.*}})
174// CHECK-NOT: call
175// CHECK: ret void
176
177void testParamContainsNonTrivial(ContainsNonTrivial a) {
178}
179
180// CHECK: define{{.*}} void @_Z26testCallContainsNonTrivialP18ContainsNonTrivial(
181// CHECK: call void @_Z27testParamContainsNonTrivial18ContainsNonTrivial(ptr noundef %{{.*}})
182// CHECK: call noundef ptr @_ZN18ContainsNonTrivialD1Ev(ptr {{[^,]*}} %{{.*}})
183
184void testCallContainsNonTrivial(ContainsNonTrivial *a) {
185  testParamContainsNonTrivial(*a);
186}
187
188namespace testThunk {
189
190// CHECK-LABEL: define{{.*}} i64 @_ZThn8_N9testThunk2D02m0Ev(
191// CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_STRONG]], align 8
192// CHECK: %[[CALL:.*]] = tail call i64 @_ZN9testThunk2D02m0Ev(
193// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds nuw %[[STRUCT_STRONG]], ptr %[[RETVAL]], i32 0, i32 0
194// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[CALL]] to ptr
195// CHECK: store ptr %[[COERCE_VAL_IP]], ptr %[[COERCE_DIVE]], align 8
196// CHECK: %[[COERCE_DIVE2:.*]] = getelementptr inbounds nuw %[[STRUCT_STRONG]], ptr %[[RETVAL]], i32 0, i32 0
197// CHECK: %[[V3:.*]] = load ptr, ptr %[[COERCE_DIVE2]], align 8
198// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint ptr %[[V3]] to i64
199// CHECK: ret i64 %[[COERCE_VAL_PI]]
200
201struct B0 {
202  virtual Strong m0();
203};
204
205struct B1 {
206  virtual Strong m0();
207};
208
209struct D0 : B0, B1 {
210  Strong m0() override;
211};
212
213Strong D0::m0() { return {}; }
214
215}
216
217namespace testNullReceiver {
218
219// CHECK-LABEL: define{{.*}} void @_ZN16testNullReceiver5test0EP1C(
220// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONG]], align 8
221// CHECK: br i1
222
223// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds nuw %[[STRUCT_STRONG]], ptr %[[AGG_TMP]], i32 0, i32 0
224// CHECK: %[[V7:.*]] = load ptr, ptr %[[COERCE_DIVE]], align 8
225// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint ptr %[[V7]] to i64
226// CHECK: call void @objc_msgSend({{.*}}, i64 %[[COERCE_VAL_PI]])
227// CHECK: br
228
229// CHECK: %[[CALL1:.*]] = call noundef ptr @_ZN6StrongD1Ev(ptr noundef nonnull align 8 dereferenceable(8) %[[AGG_TMP]])
230// CHECK: br
231
232void test0(C *c) {
233  [c passStrong:Strong()];
234}
235
236// CHECK-LABEL: define{{.*}} void @_ZN16testNullReceiver5test1EP1C(
237// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONGWEAK]], align 8
238// CHECK: br i1
239
240// CHECK: call void @objc_msgSend({{.*}}, ptr noundef %[[AGG_TMP]])
241// CHECK: br
242
243// CHECK: %[[CALL1:.*]] = call noundef ptr @_ZN10StrongWeakD1Ev(ptr noundef nonnull align 8 dereferenceable(16) %[[AGG_TMP]])
244// CHECK: br
245
246void test1(C *c) {
247  [c passStrongWeak:StrongWeak()];
248}
249
250// No null check needed.
251
252// CHECK-LABEL: define{{.*}} void @_ZN16testNullReceiver5test2EP1C(
253// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_NONTRIVIAL]], align 8
254// CHECK: call void @objc_msgSend({{.*}}, ptr noundef %[[AGG_TMP]])
255// CHECK-NEXT: call noundef ptr @_ZN10NonTrivialD1Ev(ptr noundef nonnull align 8 dereferenceable(8) %[[AGG_TMP]])
256
257void test2(C *c) {
258  [c passNonTrivial:NonTrivial()];
259}
260
261}
262