262 lines · plain
1// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc -fobjc-weak -fobjc-runtime-has-weak -emit-llvm -o - %s | FileCheck %s2// 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 %s3// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc -fobjc-weak -fobjc-runtime-has-weak -emit-llvm -o - -DTRIVIALABI %s | FileCheck %s4// 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 %s5 6// Check that structs consisting solely of __strong or __weak pointer fields are7// destructed in the callee function and structs consisting solely of __strong8// 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 TRIVIALABI18struct __attribute__((trivial_abi)) StrongWeak {19#else20struct StrongWeak {21#endif22 id fstrong;23 __weak id fweak;24};25 26#ifdef TRIVIALABI27struct __attribute__((trivial_abi)) ContainsStrongWeak {28#else29struct ContainsStrongWeak {30#endif31 StrongWeak sw;32};33 34#ifdef TRIVIALABI35struct __attribute__((trivial_abi)) DerivedStrongWeak : StrongWeak {36#else37struct DerivedStrongWeak : StrongWeak {38#endif39};40 41#ifdef TRIVIALABI42struct __attribute__((trivial_abi)) Strong {43#else44struct Strong {45#endif46 id fstrong;47};48 49template<class T>50#ifdef TRIVIALABI51struct __attribute__((trivial_abi)) S {52#else53struct S {54#endif55 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 f066// has type NonTrivial.67struct ContainsNonTrivial {68 NonTrivial f0;69 id f1;70};71 72@interface C73- (void)passStrong:(Strong)a;74- (void)passStrongWeak:(StrongWeak)a;75- (void)passNonTrivial:(NonTrivial)a;76@end77 78// CHECK: define{{.*}} void @_Z19testParamStrongWeak10StrongWeak(ptr dead_on_return noundef %{{.*}})79// CHECK: call noundef ptr @_ZN10StrongWeakD1Ev(80// CHECK-NEXT: ret void81 82void testParamStrongWeak(StrongWeak a) {83}84 85// CHECK: define{{.*}} void @_Z18testCallStrongWeakP10StrongWeak(ptr noundef %[[A:.*]])86// CHECK: %[[A_ADDR:.*]] = alloca ptr, align 887// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONGWEAK]], align 888// CHECK: store ptr %[[A]], ptr %[[A_ADDR]], align 889// CHECK: %[[V0:.*]] = load ptr, ptr %[[A_ADDR]], align 890// CHECK: %[[CALL:.*]] = call noundef ptr @_ZN10StrongWeakC1ERKS_(ptr {{[^,]*}} %[[AGG_TMP]], ptr noundef nonnull align 8 dereferenceable(16) %[[V0]])91// CHECK: call void @_Z19testParamStrongWeak10StrongWeak(ptr dead_on_return noundef %[[AGG_TMP]])92// CHECK-NOT: call93// CHECK: ret void94 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 8101// CHECK: store ptr %[[A]], ptr %[[A_ADDR]], align 8102// CHECK: %[[V0:.*]] = load ptr, ptr %[[A_ADDR]], align 8103// CHECK: %[[CALL:.*]] = call noundef ptr @_ZN10StrongWeakC1ERKS_(ptr {{[^,]*}} %[[AGG_RESULT]], ptr noundef nonnull align 8 dereferenceable(16) %[[V0]])104// CHECK: ret void105 106StrongWeak testReturnStrongWeak(StrongWeak *a) {107 return *a;108}109 110// CHECK: define{{.*}} void @_Z27testParamContainsStrongWeak18ContainsStrongWeak(ptr dead_on_return noundef %[[A:.*]])111// CHECK: call noundef ptr @_ZN18ContainsStrongWeakD1Ev(ptr {{[^,]*}} %[[A]])112 113void testParamContainsStrongWeak(ContainsStrongWeak a) {114}115 116// CHECK: define{{.*}} void @_Z26testParamDerivedStrongWeak17DerivedStrongWeak(ptr dead_on_return 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 8124// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds nuw %[[STRUCT_STRONG]], ptr %[[A]], i32 0, i32 0125// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[A_COERCE]] to ptr126// CHECK: store ptr %[[COERCE_VAL_IP]], ptr %[[COERCE_DIVE]], align 8127// CHECK: %[[CALL:.*]] = call noundef ptr @_ZN6StrongD1Ev(ptr {{[^,]*}} %[[A]])128// CHECK: ret void129 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 8137// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONG]], align 8138// CHECK: store ptr %[[A]], ptr %[[A_ADDR]], align 8139// CHECK: %[[V0:.*]] = load ptr, ptr %[[A_ADDR]], align 8140// 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 0142// CHECK: %[[V1:.*]] = load ptr, ptr %[[COERCE_DIVE]], align 8143// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint ptr %[[V1]] to i64144// CHECK: call void @_Z15testParamStrong6Strong(i64 %[[COERCE_VAL_PI]])145// CHECK: ret void146 147void testCallStrong(Strong *a) {148 testParamStrong(*a);149}150 151// CHECK: define{{.*}} i64 @_Z16testReturnStrongP6Strong(ptr noundef %[[A:.*]])152// CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_STRONG]], align 8153// CHECK: %[[A_ADDR:.*]] = alloca ptr, align 8154// CHECK: store ptr %[[A]], ptr %[[A_ADDR]], align 8155// CHECK: %[[V0:.*]] = load ptr, ptr %[[A_ADDR]], align 8156// 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 0158// CHECK: %[[V1:.*]] = load ptr, ptr %[[COERCE_DIVE]], align 8159// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint ptr %[[V1]] to i64160// CHECK: ret i64 %[[COERCE_VAL_PI]]161 162Strong testReturnStrong(Strong *a) {163 return *a;164}165 166// CHECK: define{{.*}} void @_Z21testParamWeakTemplate1SIU6__weakP11objc_objectE(ptr dead_on_return noundef %{{.*}})167// CHECK: call noundef ptr @_ZN1SIU6__weakP11objc_objectED1Ev(168// CHECK-NEXT: ret void169 170void testParamWeakTemplate(S<__weak id> a) {171}172 173// CHECK: define{{.*}} void @_Z27testParamContainsNonTrivial18ContainsNonTrivial(ptr noundef %{{.*}})174// CHECK-NOT: call175// CHECK: ret void176 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 8192// CHECK: %[[CALL:.*]] = tail call i64 @_ZN9testThunk2D02m0Ev(193// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds nuw %[[STRUCT_STRONG]], ptr %[[RETVAL]], i32 0, i32 0194// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[CALL]] to ptr195// CHECK: store ptr %[[COERCE_VAL_IP]], ptr %[[COERCE_DIVE]], align 8196// CHECK: %[[COERCE_DIVE2:.*]] = getelementptr inbounds nuw %[[STRUCT_STRONG]], ptr %[[RETVAL]], i32 0, i32 0197// CHECK: %[[V3:.*]] = load ptr, ptr %[[COERCE_DIVE2]], align 8198// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint ptr %[[V3]] to i64199// 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 8221// CHECK: br i1222 223// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds nuw %[[STRUCT_STRONG]], ptr %[[AGG_TMP]], i32 0, i32 0224// CHECK: %[[V7:.*]] = load ptr, ptr %[[COERCE_DIVE]], align 8225// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint ptr %[[V7]] to i64226// CHECK: call void @objc_msgSend({{.*}}, i64 %[[COERCE_VAL_PI]])227// CHECK: br228 229// CHECK: %[[CALL1:.*]] = call noundef ptr @_ZN6StrongD1Ev(ptr noundef nonnull align 8 dereferenceable(8) %[[AGG_TMP]])230// CHECK: br231 232void test0(C *c) {233 [c passStrong:Strong()];234}235 236// CHECK-LABEL: define{{.*}} void @_ZN16testNullReceiver5test1EP1C(237// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONGWEAK]], align 8238// CHECK: br i1239 240// CHECK: call void @objc_msgSend({{.*}}, ptr dead_on_return noundef %[[AGG_TMP]])241// CHECK: br242 243// CHECK: %[[CALL1:.*]] = call noundef ptr @_ZN10StrongWeakD1Ev(ptr noundef nonnull align 8 dereferenceable(16) %[[AGG_TMP]])244// CHECK: br245 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 8254// 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