1 | // RUN: %clang_cc1 -triple armv7-apple-darwin -target-abi aapcs -emit-llvm -o - %s | FileCheck %s |
2 | // RUN: %clang_cc1 -triple armv7-apple-darwin -target-abi apcs-gnu -emit-llvm -o - %s | FileCheck -check-prefix=APCS-GNU %s |
3 | // RUN: %clang_cc1 -triple arm-linux-androideabi -emit-llvm -o - %s | FileCheck -check-prefix=ANDROID %s |
4 | |
5 | #include <stdarg.h> |
6 | |
7 | typedef __attribute__(( ext_vector_type(2) )) int __int2; |
8 | typedef __attribute__(( ext_vector_type(3) )) char __char3; |
9 | typedef __attribute__(( ext_vector_type(5) )) char __char5; |
10 | typedef __attribute__(( ext_vector_type(9) )) char __char9; |
11 | typedef __attribute__(( ext_vector_type(19) )) char __char19; |
12 | typedef __attribute__(( ext_vector_type(3) )) short __short3; |
13 | typedef __attribute__(( ext_vector_type(5) )) short __short5; |
14 | |
15 | // Passing legal vector types as varargs. |
16 | double varargs_vec_2i(int fixed, ...) { |
17 | // CHECK: varargs_vec_2i |
18 | // CHECK: [[VAR:%.*]] = alloca <2 x i32>, align 8 |
19 | // CHECK: [[ALIGN:%.*]] = and i32 {{%.*}}, -8 |
20 | // CHECK: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8* |
21 | // CHECK: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP_ALIGN]], i32 8 |
22 | // CHECK: [[AP_CAST:%.*]] = bitcast i8* [[AP_ALIGN]] to <2 x i32>* |
23 | // CHECK: [[VEC:%.*]] = load <2 x i32>, <2 x i32>* [[AP_CAST]], align 8 |
24 | // CHECK: store <2 x i32> [[VEC]], <2 x i32>* [[VAR]], align 8 |
25 | // APCS-GNU: varargs_vec_2i |
26 | // APCS-GNU: [[VAR:%.*]] = alloca <2 x i32>, align 8 |
27 | // APCS-GNU: [[AP:%.*]] = load i8*, |
28 | // APCS-GNU: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP]], i32 8 |
29 | // APCS-GNU: [[AP_CAST:%.*]] = bitcast i8* [[AP]] to <2 x i32>* |
30 | // APCS-GNU: [[VEC:%.*]] = load <2 x i32>, <2 x i32>* [[AP_CAST]], align 4 |
31 | // APCS-GNU: store <2 x i32> [[VEC]], <2 x i32>* [[VAR]], align 8 |
32 | // ANDROID: varargs_vec_2i |
33 | // ANDROID: [[VAR:%.*]] = alloca <2 x i32>, align 8 |
34 | // ANDROID: [[ALIGN:%.*]] = and i32 {{%.*}}, -8 |
35 | // ANDROID: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8* |
36 | // ANDROID: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP_ALIGN]], i32 8 |
37 | // ANDROID: [[AP_CAST:%.*]] = bitcast i8* [[AP_ALIGN]] to <2 x i32>* |
38 | // ANDROID: [[VEC:%.*]] = load <2 x i32>, <2 x i32>* [[AP_CAST]], align 8 |
39 | // ANDROID: store <2 x i32> [[VEC]], <2 x i32>* [[VAR]], align 8 |
40 | va_list ap; |
41 | double sum = fixed; |
42 | va_start(ap, fixed); |
43 | __int2 c3 = va_arg(ap, __int2); |
44 | sum = sum + c3.x + c3.y; |
45 | va_end(ap); |
46 | return sum; |
47 | } |
48 | |
49 | double test_2i(__int2 *in) { |
50 | // CHECK: test_2i |
51 | // CHECK: call arm_aapcscc double (i32, ...) @varargs_vec_2i(i32 3, <2 x i32> {{%.*}}) |
52 | // APCS-GNU: test_2i |
53 | // APCS-GNU: call double (i32, ...) @varargs_vec_2i(i32 3, <2 x i32> {{%.*}}) |
54 | // ANDROID: test_2i |
55 | // ANDROID: call double (i32, ...) @varargs_vec_2i(i32 3, <2 x i32> {{%.*}}) |
56 | return varargs_vec_2i(3, *in); |
57 | } |
58 | |
59 | double varargs_vec_3c(int fixed, ...) { |
60 | // CHECK: varargs_vec_3c |
61 | // CHECK: alloca <3 x i8>, align 4 |
62 | // CHECK: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP:%.*]], i32 4 |
63 | // CHECK: bitcast i8* [[AP]] to <3 x i8>* |
64 | // APCS-GNU: varargs_vec_3c |
65 | // APCS-GNU: alloca <3 x i8>, align 4 |
66 | // APCS-GNU: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP:%.*]], i32 4 |
67 | // APCS-GNU: bitcast i8* [[AP]] to <3 x i8>* |
68 | // ANDROID: varargs_vec_3c |
69 | // ANDROID: alloca <3 x i8>, align 4 |
70 | // ANDROID: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP:%.*]], i32 4 |
71 | // ANDROID: bitcast i8* [[AP]] to <3 x i8>* |
72 | va_list ap; |
73 | double sum = fixed; |
74 | va_start(ap, fixed); |
75 | __char3 c3 = va_arg(ap, __char3); |
76 | sum = sum + c3.x + c3.y; |
77 | va_end(ap); |
78 | return sum; |
79 | } |
80 | |
81 | double test_3c(__char3 *in) { |
82 | // CHECK: test_3c |
83 | // CHECK: call arm_aapcscc double (i32, ...) @varargs_vec_3c(i32 3, i32 {{%.*}}) |
84 | // APCS-GNU: test_3c |
85 | // APCS-GNU: call double (i32, ...) @varargs_vec_3c(i32 3, i32 {{%.*}}) |
86 | // ANDROID: test_3c |
87 | // ANDROID: call double (i32, ...) @varargs_vec_3c(i32 3, <3 x i8> {{%.*}}) |
88 | return varargs_vec_3c(3, *in); |
89 | } |
90 | |
91 | double varargs_vec_5c(int fixed, ...) { |
92 | // CHECK: varargs_vec_5c |
93 | // CHECK: [[VAR:%.*]] = alloca <5 x i8>, align 8 |
94 | // CHECK: [[ALIGN:%.*]] = and i32 {{%.*}}, -8 |
95 | // CHECK: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8* |
96 | // CHECK: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP_ALIGN]], i32 8 |
97 | // CHECK: [[AP_CAST:%.*]] = bitcast i8* [[AP_ALIGN]] to <5 x i8>* |
98 | // CHECK: [[VEC:%.*]] = load <5 x i8>, <5 x i8>* [[AP_CAST]], align 8 |
99 | // CHECK: store <5 x i8> [[VEC]], <5 x i8>* [[VAR]], align 8 |
100 | // APCS-GNU: varargs_vec_5c |
101 | // APCS-GNU: [[VAR:%.*]] = alloca <5 x i8>, align 8 |
102 | // APCS-GNU: [[AP:%.*]] = load i8*, |
103 | // APCS-GNU: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP]], i32 8 |
104 | // APCS-GNU: [[AP_CAST:%.*]] = bitcast i8* [[AP]] to <5 x i8>* |
105 | // APCS-GNU: [[VEC:%.*]] = load <5 x i8>, <5 x i8>* [[AP_CAST]], align 4 |
106 | // APCS-GNU: store <5 x i8> [[VEC]], <5 x i8>* [[VAR]], align 8 |
107 | // ANDROID: varargs_vec_5c |
108 | // ANDROID: [[VAR:%.*]] = alloca <5 x i8>, align 8 |
109 | // ANDROID: [[ALIGN:%.*]] = and i32 {{%.*}}, -8 |
110 | // ANDROID: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8* |
111 | // ANDROID: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP_ALIGN]], i32 8 |
112 | // ANDROID: [[AP_CAST:%.*]] = bitcast i8* [[AP_ALIGN]] to <5 x i8>* |
113 | // ANDROID: [[VEC:%.*]] = load <5 x i8>, <5 x i8>* [[AP_CAST]], align 8 |
114 | // ANDROID: store <5 x i8> [[VEC]], <5 x i8>* [[VAR]], align 8 |
115 | va_list ap; |
116 | double sum = fixed; |
117 | va_start(ap, fixed); |
118 | __char5 c5 = va_arg(ap, __char5); |
119 | sum = sum + c5.x + c5.y; |
120 | va_end(ap); |
121 | return sum; |
122 | } |
123 | |
124 | double test_5c(__char5 *in) { |
125 | // CHECK: test_5c |
126 | // CHECK: call arm_aapcscc double (i32, ...) @varargs_vec_5c(i32 5, <2 x i32> {{%.*}}) |
127 | // APCS-GNU: test_5c |
128 | // APCS-GNU: call double (i32, ...) @varargs_vec_5c(i32 5, <2 x i32> {{%.*}}) |
129 | // ANDROID: test_5c |
130 | // ANDROID: call double (i32, ...) @varargs_vec_5c(i32 5, <2 x i32> {{%.*}}) |
131 | return varargs_vec_5c(5, *in); |
132 | } |
133 | |
134 | double varargs_vec_9c(int fixed, ...) { |
135 | // CHECK: varargs_vec_9c |
136 | // CHECK: [[VAR:%.*]] = alloca <9 x i8>, align 16 |
137 | // CHECK: [[ALIGN:%.*]] = and i32 {{%.*}}, -8 |
138 | // CHECK: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8* |
139 | // CHECK: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP_ALIGN]], i32 16 |
140 | // CHECK: [[AP_CAST:%.*]] = bitcast i8* [[AP_ALIGN]] to <9 x i8>* |
141 | // CHECK: [[T0:%.*]] = load <9 x i8>, <9 x i8>* [[AP_CAST]], align 8 |
142 | // CHECK: store <9 x i8> [[T0]], <9 x i8>* [[VAR]], align 16 |
143 | // APCS-GNU: varargs_vec_9c |
144 | // APCS-GNU: [[VAR:%.*]] = alloca <9 x i8>, align 16 |
145 | // APCS-GNU: [[AP:%.*]] = load i8*, |
146 | // APCS-GNU: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP]], i32 16 |
147 | // APCS-GNU: [[AP_CAST:%.*]] = bitcast i8* [[AP]] to <9 x i8>* |
148 | // APCS-GNU: [[VEC:%.*]] = load <9 x i8>, <9 x i8>* [[AP_CAST]], align 4 |
149 | // APCS-GNU: store <9 x i8> [[VEC]], <9 x i8>* [[VAR]], align 16 |
150 | // ANDROID: varargs_vec_9c |
151 | // ANDROID: [[VAR:%.*]] = alloca <9 x i8>, align 16 |
152 | // ANDROID: [[ALIGN:%.*]] = and i32 {{%.*}}, -8 |
153 | // ANDROID: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8* |
154 | // ANDROID: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP_ALIGN]], i32 16 |
155 | // ANDROID: [[AP_CAST:%.*]] = bitcast i8* [[AP_ALIGN]] to <9 x i8>* |
156 | // ANDROID: [[T0:%.*]] = load <9 x i8>, <9 x i8>* [[AP_CAST]], align 8 |
157 | // ANDROID: store <9 x i8> [[T0]], <9 x i8>* [[VAR]], align 16 |
158 | va_list ap; |
159 | double sum = fixed; |
160 | va_start(ap, fixed); |
161 | __char9 c9 = va_arg(ap, __char9); |
162 | sum = sum + c9.x + c9.y; |
163 | va_end(ap); |
164 | return sum; |
165 | } |
166 | |
167 | double test_9c(__char9 *in) { |
168 | // CHECK: test_9c |
169 | // CHECK: call arm_aapcscc double (i32, ...) @varargs_vec_9c(i32 9, <4 x i32> {{%.*}}) |
170 | // APCS-GNU: test_9c |
171 | // APCS-GNU: call double (i32, ...) @varargs_vec_9c(i32 9, <4 x i32> {{%.*}}) |
172 | // ANDROID: test_9c |
173 | // ANDROID: call double (i32, ...) @varargs_vec_9c(i32 9, <4 x i32> {{%.*}}) |
174 | return varargs_vec_9c(9, *in); |
175 | } |
176 | |
177 | double varargs_vec_19c(int fixed, ...) { |
178 | // CHECK: varargs_vec_19c |
179 | // CHECK: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP:%.*]], i32 4 |
180 | // CHECK: [[VAR:%.*]] = bitcast i8* [[AP]] to <19 x i8>** |
181 | // CHECK: [[VAR2:%.*]] = load <19 x i8>*, <19 x i8>** [[VAR]] |
182 | // APCS-GNU: varargs_vec_19c |
183 | // APCS-GNU: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP:%.*]], i32 4 |
184 | // APCS-GNU: [[VAR:%.*]] = bitcast i8* [[AP]] to <19 x i8>** |
185 | // APCS-GNU: [[VAR2:%.*]] = load <19 x i8>*, <19 x i8>** [[VAR]] |
186 | // ANDROID: varargs_vec_19c |
187 | // ANDROID: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP:%.*]], i32 4 |
188 | // ANDROID: [[VAR:%.*]] = bitcast i8* [[AP]] to <19 x i8>** |
189 | // ANDROID: [[VAR2:%.*]] = load <19 x i8>*, <19 x i8>** [[VAR]] |
190 | va_list ap; |
191 | double sum = fixed; |
192 | va_start(ap, fixed); |
193 | __char19 c19 = va_arg(ap, __char19); |
194 | sum = sum + c19.x + c19.y; |
195 | va_end(ap); |
196 | return sum; |
197 | } |
198 | |
199 | double test_19c(__char19 *in) { |
200 | // CHECK: test_19c |
201 | // CHECK: call arm_aapcscc double (i32, ...) @varargs_vec_19c(i32 19, <19 x i8>* {{%.*}}) |
202 | // APCS-GNU: test_19c |
203 | // APCS-GNU: call double (i32, ...) @varargs_vec_19c(i32 19, <19 x i8>* {{%.*}}) |
204 | // ANDROID: test_19c |
205 | // ANDROID: call double (i32, ...) @varargs_vec_19c(i32 19, <19 x i8>* {{%.*}}) |
206 | return varargs_vec_19c(19, *in); |
207 | } |
208 | |
209 | double varargs_vec_3s(int fixed, ...) { |
210 | // CHECK: varargs_vec_3s |
211 | // CHECK: alloca <3 x i16>, align 8 |
212 | // CHECK: [[ALIGN:%.*]] = and i32 {{%.*}}, -8 |
213 | // CHECK: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8* |
214 | // CHECK: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP_ALIGN]], i32 8 |
215 | // CHECK: bitcast i8* [[AP_ALIGN]] to <3 x i16>* |
216 | // APCS-GNU: varargs_vec_3s |
217 | // APCS-GNU: [[VAR:%.*]] = alloca <3 x i16>, align 8 |
218 | // APCS-GNU: [[AP:%.*]] = load i8*, |
219 | // APCS-GNU: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP]], i32 8 |
220 | // APCS-GNU: [[AP_CAST:%.*]] = bitcast i8* [[AP]] to <3 x i16>* |
221 | // APCS-GNU: [[VEC:%.*]] = load <3 x i16>, <3 x i16>* [[AP_CAST]], align 4 |
222 | // ANDROID: varargs_vec_3s |
223 | // ANDROID: alloca <3 x i16>, align 8 |
224 | // ANDROID: [[ALIGN:%.*]] = and i32 {{%.*}}, -8 |
225 | // ANDROID: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8* |
226 | // ANDROID: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP_ALIGN]], i32 8 |
227 | // ANDROID: bitcast i8* [[AP_ALIGN]] to <3 x i16>* |
228 | va_list ap; |
229 | double sum = fixed; |
230 | va_start(ap, fixed); |
231 | __short3 c3 = va_arg(ap, __short3); |
232 | sum = sum + c3.x + c3.y; |
233 | va_end(ap); |
234 | return sum; |
235 | } |
236 | |
237 | double test_3s(__short3 *in) { |
238 | // CHECK: test_3s |
239 | // CHECK: call arm_aapcscc double (i32, ...) @varargs_vec_3s(i32 3, <2 x i32> {{%.*}}) |
240 | // APCS-GNU: test_3s |
241 | // APCS-GNU: call double (i32, ...) @varargs_vec_3s(i32 3, <2 x i32> {{%.*}}) |
242 | // ANDROID: test_3s |
243 | // ANDROID: call double (i32, ...) @varargs_vec_3s(i32 3, <3 x i16> {{%.*}}) |
244 | return varargs_vec_3s(3, *in); |
245 | } |
246 | |
247 | double varargs_vec_5s(int fixed, ...) { |
248 | // CHECK: varargs_vec_5s |
249 | // CHECK: [[VAR_ALIGN:%.*]] = alloca <5 x i16>, align 16 |
250 | // CHECK: [[ALIGN:%.*]] = and i32 {{%.*}}, -8 |
251 | // CHECK: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8* |
252 | // CHECK: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP_ALIGN]], i32 16 |
253 | // CHECK: [[AP_CAST:%.*]] = bitcast i8* [[AP_ALIGN]] to <5 x i16>* |
254 | // CHECK: [[VEC:%.*]] = load <5 x i16>, <5 x i16>* [[AP_CAST]], align 8 |
255 | // CHECK: store <5 x i16> [[VEC]], <5 x i16>* [[VAR_ALIGN]], align 16 |
256 | // APCS-GNU: varargs_vec_5s |
257 | // APCS-GNU: [[VAR:%.*]] = alloca <5 x i16>, align 16 |
258 | // APCS-GNU: [[AP:%.*]] = load i8*, |
259 | // APCS-GNU: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP]], i32 16 |
260 | // APCS-GNU: [[AP_CAST:%.*]] = bitcast i8* [[AP]] to <5 x i16>* |
261 | // APCS-GNU: [[VEC:%.*]] = load <5 x i16>, <5 x i16>* [[AP_CAST]], align 4 |
262 | // ANDROID: varargs_vec_5s |
263 | // ANDROID: [[VAR_ALIGN:%.*]] = alloca <5 x i16>, align 16 |
264 | // ANDROID: [[ALIGN:%.*]] = and i32 {{%.*}}, -8 |
265 | // ANDROID: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8* |
266 | // ANDROID: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP_ALIGN]], i32 16 |
267 | // ANDROID: [[AP_CAST:%.*]] = bitcast i8* [[AP_ALIGN]] to <5 x i16>* |
268 | // ANDROID: [[VEC:%.*]] = load <5 x i16>, <5 x i16>* [[AP_CAST]], align 8 |
269 | // ANDROID: store <5 x i16> [[VEC]], <5 x i16>* [[VAR_ALIGN]], align 16 |
270 | va_list ap; |
271 | double sum = fixed; |
272 | va_start(ap, fixed); |
273 | __short5 c5 = va_arg(ap, __short5); |
274 | sum = sum + c5.x + c5.y; |
275 | va_end(ap); |
276 | return sum; |
277 | } |
278 | |
279 | double test_5s(__short5 *in) { |
280 | // CHECK: test_5s |
281 | // CHECK: call arm_aapcscc double (i32, ...) @varargs_vec_5s(i32 5, <4 x i32> {{%.*}}) |
282 | // APCS-GNU: test_5s |
283 | // APCS-GNU: call double (i32, ...) @varargs_vec_5s(i32 5, <4 x i32> {{%.*}}) |
284 | // ANDROID: test_5s |
285 | // ANDROID: call double (i32, ...) @varargs_vec_5s(i32 5, <4 x i32> {{%.*}}) |
286 | return varargs_vec_5s(5, *in); |
287 | } |
288 | |
289 | // Pass struct as varargs. |
290 | typedef struct |
291 | { |
292 | __int2 i2; |
293 | float f; |
294 | } StructWithVec; |
295 | |
296 | double varargs_struct(int fixed, ...) { |
297 | // CHECK: varargs_struct |
298 | // CHECK: [[ALIGN:%.*]] = and i32 {{%.*}}, -8 |
299 | // CHECK: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8* |
300 | // CHECK: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP_ALIGN]], i32 16 |
301 | // CHECK: bitcast i8* [[AP_ALIGN]] to %struct.StructWithVec* |
302 | // APCS-GNU: varargs_struct |
303 | // APCS-GNU: [[VAR_ALIGN:%.*]] = alloca %struct.StructWithVec |
304 | // APCS-GNU: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* {{%.*}}, i32 16 |
305 | // APCS-GNU: bitcast %struct.StructWithVec* [[VAR_ALIGN]] to i8* |
306 | // APCS-GNU: call void @llvm.memcpy |
307 | // ANDROID: varargs_struct |
308 | // ANDROID: [[ALIGN:%.*]] = and i32 {{%.*}}, -8 |
309 | // ANDROID: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8* |
310 | // ANDROID: [[AP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[AP_ALIGN]], i32 16 |
311 | // ANDROID: bitcast i8* [[AP_ALIGN]] to %struct.StructWithVec* |
312 | va_list ap; |
313 | double sum = fixed; |
314 | va_start(ap, fixed); |
315 | StructWithVec c3 = va_arg(ap, StructWithVec); |
316 | sum = sum + c3.i2.x + c3.i2.y + c3.f; |
317 | va_end(ap); |
318 | return sum; |
319 | } |
320 | |
321 | double test_struct(StructWithVec* d) { |
322 | // CHECK: test_struct |
323 | // CHECK: call arm_aapcscc double (i32, ...) @varargs_struct(i32 3, [2 x i64] {{%.*}}) |
324 | // APCS-GNU: test_struct |
325 | // APCS-GNU: call double (i32, ...) @varargs_struct(i32 3, [2 x i64] {{%.*}}) |
326 | // ANDROID: test_struct |
327 | // ANDROID: call double (i32, ...) @varargs_struct(i32 3, [2 x i64] {{%.*}}) |
328 | return varargs_struct(3, *d); |
329 | } |
330 | |