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