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