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 | |
17 | #ifdef TRIVIALABI |
18 | struct __attribute__((trivial_abi)) StrongWeak { |
19 | #else |
20 | struct StrongWeak { |
21 | #endif |
22 | id fstrong; |
23 | __weak id fweak; |
24 | }; |
25 | |
26 | #ifdef TRIVIALABI |
27 | struct __attribute__((trivial_abi)) ContainsStrongWeak { |
28 | #else |
29 | struct ContainsStrongWeak { |
30 | #endif |
31 | StrongWeak sw; |
32 | }; |
33 | |
34 | #ifdef TRIVIALABI |
35 | struct __attribute__((trivial_abi)) DerivedStrongWeak : StrongWeak { |
36 | #else |
37 | struct DerivedStrongWeak : StrongWeak { |
38 | #endif |
39 | }; |
40 | |
41 | #ifdef TRIVIALABI |
42 | struct __attribute__((trivial_abi)) Strong { |
43 | #else |
44 | struct Strong { |
45 | #endif |
46 | id fstrong; |
47 | }; |
48 | |
49 | template<class T> |
50 | #ifdef TRIVIALABI |
51 | struct __attribute__((trivial_abi)) S { |
52 | #else |
53 | struct S { |
54 | #endif |
55 | T a; |
56 | }; |
57 | |
58 | struct 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. |
67 | struct ContainsNonTrivial { |
68 | NonTrivial f0; |
69 | id f1; |
70 | }; |
71 | |
72 | // CHECK: define void @_Z19testParamStrongWeak10StrongWeak(%[[STRUCT_STRONGWEAK]]* %{{.*}}) |
73 | // CHECK: call %struct.StrongWeak* @_ZN10StrongWeakD1Ev( |
74 | // CHECK-NEXT: ret void |
75 | |
76 | void testParamStrongWeak(StrongWeak a) { |
77 | } |
78 | |
79 | // CHECK: define void @_Z18testCallStrongWeakP10StrongWeak(%[[STRUCT_STRONGWEAK]]* %[[A:.*]]) |
80 | // CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONGWEAK]]*, align 8 |
81 | // CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONGWEAK]], align 8 |
82 | // CHECK: store %[[STRUCT_STRONGWEAK]]* %[[A]], %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8 |
83 | // CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGWEAK]]*, %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8 |
84 | // CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONGWEAK]]* @_ZN10StrongWeakC1ERKS_(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]], %[[STRUCT_STRONGWEAK]]* dereferenceable(16) %[[V0]]) |
85 | // CHECK: call void @_Z19testParamStrongWeak10StrongWeak(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]]) |
86 | // CHECK-NOT: call |
87 | // CHECK: ret void |
88 | |
89 | void testCallStrongWeak(StrongWeak *a) { |
90 | testParamStrongWeak(*a); |
91 | } |
92 | |
93 | // CHECK: define void @_Z20testReturnStrongWeakP10StrongWeak(%[[STRUCT_STRONGWEAK:.*]]* noalias sret %[[AGG_RESULT:.*]], %[[STRUCT_STRONGWEAK]]* %[[A:.*]]) |
94 | // CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONGWEAK]]*, align 8 |
95 | // CHECK: store %[[STRUCT_STRONGWEAK]]* %[[A]], %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8 |
96 | // CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGWEAK]]*, %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8 |
97 | // CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONGWEAK]]* @_ZN10StrongWeakC1ERKS_(%[[STRUCT_STRONGWEAK]]* %[[AGG_RESULT]], %[[STRUCT_STRONGWEAK]]* dereferenceable(16) %[[V0]]) |
98 | // CHECK: ret void |
99 | |
100 | StrongWeak testReturnStrongWeak(StrongWeak *a) { |
101 | return *a; |
102 | } |
103 | |
104 | // CHECK: define void @_Z27testParamContainsStrongWeak18ContainsStrongWeak(%[[STRUCT_CONTAINSSTRONGWEAK]]* %[[A:.*]]) |
105 | // CHECK: call %[[STRUCT_CONTAINSSTRONGWEAK]]* @_ZN18ContainsStrongWeakD1Ev(%[[STRUCT_CONTAINSSTRONGWEAK]]* %[[A]]) |
106 | |
107 | void testParamContainsStrongWeak(ContainsStrongWeak a) { |
108 | } |
109 | |
110 | // CHECK: define void @_Z26testParamDerivedStrongWeak17DerivedStrongWeak(%[[STRUCT_DERIVEDSTRONGWEAK]]* %[[A:.*]]) |
111 | // CHECK: call %[[STRUCT_DERIVEDSTRONGWEAK]]* @_ZN17DerivedStrongWeakD1Ev(%[[STRUCT_DERIVEDSTRONGWEAK]]* %[[A]]) |
112 | |
113 | void testParamDerivedStrongWeak(DerivedStrongWeak a) { |
114 | } |
115 | |
116 | // CHECK: define void @_Z15testParamStrong6Strong(i64 %[[A_COERCE:.*]]) |
117 | // CHECK: %[[A:.*]] = alloca %[[STRUCT_STRONG]], align 8 |
118 | // CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[A]], i32 0, i32 0 |
119 | // CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[A_COERCE]] to i8* |
120 | // CHECK: store i8* %[[COERCE_VAL_IP]], i8** %[[COERCE_DIVE]], align 8 |
121 | // CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONG]]* @_ZN6StrongD1Ev(%[[STRUCT_STRONG]]* %[[A]]) |
122 | // CHECK: ret void |
123 | |
124 | // CHECK: define linkonce_odr %[[STRUCT_STRONG]]* @_ZN6StrongD1Ev( |
125 | |
126 | void testParamStrong(Strong a) { |
127 | } |
128 | |
129 | // CHECK: define void @_Z14testCallStrongP6Strong(%[[STRUCT_STRONG]]* %[[A:.*]]) |
130 | // CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONG]]*, align 8 |
131 | // CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONG]], align 8 |
132 | // CHECK: store %[[STRUCT_STRONG]]* %[[A]], %[[STRUCT_STRONG]]** %[[A_ADDR]], align 8 |
133 | // CHECK: %[[V0:.*]] = load %[[STRUCT_STRONG]]*, %[[STRUCT_STRONG]]** %[[A_ADDR]], align 8 |
134 | // CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONG]]* @_ZN6StrongC1ERKS_(%[[STRUCT_STRONG]]* %[[AGG_TMP]], %[[STRUCT_STRONG]]* dereferenceable(8) %[[V0]]) |
135 | // CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[AGG_TMP]], i32 0, i32 0 |
136 | // CHECK: %[[V1:.*]] = load i8*, i8** %[[COERCE_DIVE]], align 8 |
137 | // CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i8* %[[V1]] to i64 |
138 | // CHECK: call void @_Z15testParamStrong6Strong(i64 %[[COERCE_VAL_PI]]) |
139 | // CHECK: ret void |
140 | |
141 | void testCallStrong(Strong *a) { |
142 | testParamStrong(*a); |
143 | } |
144 | |
145 | // CHECK: define i64 @_Z16testReturnStrongP6Strong(%[[STRUCT_STRONG]]* %[[A:.*]]) |
146 | // CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_STRONG]], align 8 |
147 | // CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONG]]*, align 8 |
148 | // CHECK: store %[[STRUCT_STRONG]]* %[[A]], %[[STRUCT_STRONG]]** %[[A_ADDR]], align 8 |
149 | // CHECK: %[[V0:.*]] = load %[[STRUCT_STRONG]]*, %[[STRUCT_STRONG]]** %[[A_ADDR]], align 8 |
150 | // CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONG]]* @_ZN6StrongC1ERKS_(%[[STRUCT_STRONG]]* %[[RETVAL]], %[[STRUCT_STRONG]]* dereferenceable(8) %[[V0]]) |
151 | // CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[RETVAL]], i32 0, i32 0 |
152 | // CHECK: %[[V1:.*]] = load i8*, i8** %[[COERCE_DIVE]], align 8 |
153 | // CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i8* %[[V1]] to i64 |
154 | // CHECK: ret i64 %[[COERCE_VAL_PI]] |
155 | |
156 | Strong testReturnStrong(Strong *a) { |
157 | return *a; |
158 | } |
159 | |
160 | // CHECK: define void @_Z21testParamWeakTemplate1SIU6__weakP11objc_objectE(%[[STRUCT_S]]* %{{.*}}) |
161 | // CHECK: call %struct.S* @_ZN1SIU6__weakP11objc_objectED1Ev( |
162 | // CHECK-NEXT: ret void |
163 | |
164 | void testParamWeakTemplate(S<__weak id> a) { |
165 | } |
166 | |
167 | // CHECK: define void @_Z27testParamContainsNonTrivial18ContainsNonTrivial(%[[STRUCT_CONTAINSNONTRIVIAL]]* %{{.*}}) |
168 | // CHECK-NOT: call |
169 | // CHECK: ret void |
170 | |
171 | void testParamContainsNonTrivial(ContainsNonTrivial a) { |
172 | } |
173 | |
174 | // CHECK: define void @_Z26testCallContainsNonTrivialP18ContainsNonTrivial( |
175 | // CHECK: call void @_Z27testParamContainsNonTrivial18ContainsNonTrivial(%[[STRUCT_CONTAINSNONTRIVIAL]]* %{{.*}}) |
176 | // CHECK: call %struct.ContainsNonTrivial* @_ZN18ContainsNonTrivialD1Ev(%[[STRUCT_CONTAINSNONTRIVIAL]]* %{{.*}}) |
177 | |
178 | void testCallContainsNonTrivial(ContainsNonTrivial *a) { |
179 | testParamContainsNonTrivial(*a); |
180 | } |
181 | |