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
4#include <stdarg.h>
5
6typedef __attribute__(( ext_vector_type(2) ))  int __int2;
7typedef __attribute__(( ext_vector_type(3) ))  char __char3;
8typedef __attribute__(( ext_vector_type(5) ))  char __char5;
9typedef __attribute__(( ext_vector_type(9) ))  char __char9;
10typedef __attribute__(( ext_vector_type(19) )) char __char19;
11typedef __attribute__(( ext_vector_type(3) ))  short __short3;
12typedef __attribute__(( ext_vector_type(5) ))  short __short5;
13
14// Passing legal vector types as varargs.
15double varargs_vec_2i(int fixed, ...) {
16// CHECK: varargs_vec_2i
17// CHECK: alloca <2 x i32>, align 8
18// CHECK: [[ALIGN:%.*]] = and i32 [[VAR:%.*]], -8
19// CHECK: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8*
20// CHECK: [[AP_NEXT:%.*]] = getelementptr i8* [[AP_ALIGN]], i32 8
21// CHECK: bitcast i8* [[AP_ALIGN]] to <2 x i32>*
22// APCS-GNU: varargs_vec_2i
23// APCS-GNU: alloca <2 x i32>, align 8
24// APCS-GNU: [[VAR_ALIGN:%.*]] = alloca <2 x i32>
25// APCS-GNU: [[AP_NEXT:%.*]] = getelementptr i8* {{%.*}}, i32 8
26// APCS-GNU: bitcast <2 x i32>* [[VAR_ALIGN]] to i8*
27// APCS-GNU: call void @llvm.memcpy
28// APCS-GNU: load <2 x i32>* [[VAR_ALIGN]]
29  va_list ap;
30  double sum = fixed;
31  va_start(ap, fixed);
32  __int2 c3 = va_arg(ap, __int2);
33  sum = sum + c3.x + c3.y;
34  va_end(ap);
35  return sum;
36}
37
38double test_2i(__int2 *in) {
39// CHECK: test_2i
40// CHECK: call arm_aapcscc double (i32, ...)* @varargs_vec_2i(i32 3, <2 x i32> {{%.*}})
41// APCS-GNU: test_2i
42// APCS-GNU: call double (i32, ...)* @varargs_vec_2i(i32 3, <2 x i32> {{%.*}})
43  return varargs_vec_2i(3, *in);
44}
45
46double varargs_vec_3c(int fixed, ...) {
47// CHECK: varargs_vec_3c
48// CHECK: alloca <3 x i8>, align 4
49// CHECK: [[AP_NEXT:%.*]] = getelementptr i8* [[AP:%.*]], i32 4
50// CHECK: bitcast i8* [[AP]] to <3 x i8>*
51// APCS-GNU: varargs_vec_3c
52// APCS-GNU: alloca <3 x i8>, align 4
53// APCS-GNU: [[AP_NEXT:%.*]] = getelementptr i8* [[AP:%.*]], i32 4
54// APCS-GNU: bitcast i8* [[AP]] to <3 x i8>*
55  va_list ap;
56  double sum = fixed;
57  va_start(ap, fixed);
58  __char3 c3 = va_arg(ap, __char3);
59  sum = sum + c3.x + c3.y;
60  va_end(ap);
61  return sum;
62}
63
64double test_3c(__char3 *in) {
65// CHECK: test_3c
66// CHECK: call arm_aapcscc double (i32, ...)* @varargs_vec_3c(i32 3, i32 {{%.*}})
67// APCS-GNU: test_3c
68// APCS-GNU: call double (i32, ...)* @varargs_vec_3c(i32 3, i32 {{%.*}})
69  return varargs_vec_3c(3, *in);
70}
71
72double varargs_vec_5c(int fixed, ...) {
73// CHECK: varargs_vec_5c
74// CHECK: alloca <5 x i8>, align 8
75// CHECK: [[ALIGN:%.*]] = and i32 {{%.*}}, -8
76// CHECK: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8*
77// CHECK: [[AP_NEXT:%.*]] = getelementptr i8* [[AP_ALIGN]], i32 8
78// CHECK: bitcast i8* [[AP_ALIGN]] to <5 x i8>*
79// APCS-GNU: varargs_vec_5c
80// APCS-GNU: alloca <5 x i8>, align 8
81// APCS-GNU: [[VAR_ALIGN:%.*]] = alloca <5 x i8>
82// APCS-GNU: [[AP_NEXT:%.*]] = getelementptr i8* {{%.*}}, i32 8
83// APCS-GNU: bitcast <5 x i8>* [[VAR_ALIGN]] to i8*
84// APCS-GNU: call void @llvm.memcpy
85// APCS-GNU: load <5 x i8>* [[VAR_ALIGN]]
86  va_list ap;
87  double sum = fixed;
88  va_start(ap, fixed);
89  __char5 c5 = va_arg(ap, __char5);
90  sum = sum + c5.x + c5.y;
91  va_end(ap);
92  return sum;
93}
94
95double test_5c(__char5 *in) {
96// CHECK: test_5c
97// CHECK: call arm_aapcscc double (i32, ...)* @varargs_vec_5c(i32 5, <2 x i32> {{%.*}})
98// APCS-GNU: test_5c
99// APCS-GNU: call double (i32, ...)* @varargs_vec_5c(i32 5, <2 x i32> {{%.*}})
100  return varargs_vec_5c(5, *in);
101}
102
103double varargs_vec_9c(int fixed, ...) {
104// CHECK: varargs_vec_9c
105// CHECK: alloca <9 x i8>, align 16
106// CHECK: [[VAR_ALIGN:%.*]] = alloca <9 x i8>
107// CHECK: [[ALIGN:%.*]] = and i32 {{%.*}}, -8
108// CHECK: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8*
109// CHECK: [[AP_NEXT:%.*]] = getelementptr i8* [[AP_ALIGN]], i32 16
110// CHECK: bitcast <9 x i8>* [[VAR_ALIGN]] to i8*
111// CHECK: call void @llvm.memcpy
112// CHECK: load <9 x i8>* [[VAR_ALIGN]]
113// APCS-GNU: varargs_vec_9c
114// APCS-GNU: alloca <9 x i8>, align 16
115// APCS-GNU: [[VAR_ALIGN:%.*]] = alloca <9 x i8>
116// APCS-GNU: [[AP_NEXT:%.*]] = getelementptr i8* {{%.*}}, i32 16
117// APCS-GNU: bitcast <9 x i8>* [[VAR_ALIGN]] to i8*
118// APCS-GNU: call void @llvm.memcpy
119// APCS-GNU: load <9 x i8>* [[VAR_ALIGN]]
120  va_list ap;
121  double sum = fixed;
122  va_start(ap, fixed);
123  __char9 c9 = va_arg(ap, __char9);
124  sum = sum + c9.x + c9.y;
125  va_end(ap);
126  return sum;
127}
128
129double test_9c(__char9 *in) {
130// CHECK: test_9c
131// CHECK: call arm_aapcscc double (i32, ...)* @varargs_vec_9c(i32 9, <4 x i32> {{%.*}})
132// APCS-GNU: test_9c
133// APCS-GNU: call double (i32, ...)* @varargs_vec_9c(i32 9, <4 x i32> {{%.*}})
134  return varargs_vec_9c(9, *in);
135}
136
137double varargs_vec_19c(int fixed, ...) {
138// CHECK: varargs_vec_19c
139// CHECK: [[AP_NEXT:%.*]] = getelementptr i8* [[AP:%.*]], i32 4
140// CHECK: [[VAR:%.*]] = bitcast i8* [[AP]] to i8**
141// CHECK: [[VAR2:%.*]] = load i8** [[VAR]]
142// CHECK: bitcast i8* [[VAR2]] to <19 x i8>*
143// APCS-GNU: varargs_vec_19c
144// APCS-GNU: [[AP_NEXT:%.*]] = getelementptr i8* [[AP:%.*]], i32 4
145// APCS-GNU: [[VAR:%.*]] = bitcast i8* [[AP]] to i8**
146// APCS-GNU: [[VAR2:%.*]] = load i8** [[VAR]]
147// APCS-GNU: bitcast i8* [[VAR2]] to <19 x i8>*
148  va_list ap;
149  double sum = fixed;
150  va_start(ap, fixed);
151  __char19 c19 = va_arg(ap, __char19);
152  sum = sum + c19.x + c19.y;
153  va_end(ap);
154  return sum;
155}
156
157double test_19c(__char19 *in) {
158// CHECK: test_19c
159// CHECK: call arm_aapcscc double (i32, ...)* @varargs_vec_19c(i32 19, <19 x i8>* {{%.*}})
160// APCS-GNU: test_19c
161// APCS-GNU: call double (i32, ...)* @varargs_vec_19c(i32 19, <19 x i8>* {{%.*}})
162  return varargs_vec_19c(19, *in);
163}
164
165double varargs_vec_3s(int fixed, ...) {
166// CHECK: varargs_vec_3s
167// CHECK: alloca <3 x i16>, align 8
168// CHECK: [[ALIGN:%.*]] = and i32 {{%.*}}, -8
169// CHECK: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8*
170// CHECK: [[AP_NEXT:%.*]] = getelementptr i8* [[AP_ALIGN]], i32 8
171// CHECK: bitcast i8* [[AP_ALIGN]] to <3 x i16>*
172// APCS-GNU: varargs_vec_3s
173// APCS-GNU: alloca <3 x i16>, align 8
174// APCS-GNU: [[VAR_ALIGN:%.*]] = alloca <3 x i16>
175// APCS-GNU: [[AP_NEXT:%.*]] = getelementptr i8* {{%.*}}, i32 8
176// APCS-GNU: bitcast <3 x i16>* [[VAR_ALIGN]] to i8*
177// APCS-GNU: call void @llvm.memcpy
178// APCS-GNU: load <3 x i16>* [[VAR_ALIGN]]
179  va_list ap;
180  double sum = fixed;
181  va_start(ap, fixed);
182  __short3 c3 = va_arg(ap, __short3);
183  sum = sum + c3.x + c3.y;
184  va_end(ap);
185  return sum;
186}
187
188double test_3s(__short3 *in) {
189// CHECK: test_3s
190// CHECK: call arm_aapcscc double (i32, ...)* @varargs_vec_3s(i32 3, <2 x i32> {{%.*}})
191// APCS-GNU: test_3s
192// APCS-GNU: call double (i32, ...)* @varargs_vec_3s(i32 3, <2 x i32> {{%.*}})
193  return varargs_vec_3s(3, *in);
194}
195
196double varargs_vec_5s(int fixed, ...) {
197// CHECK: varargs_vec_5s
198// CHECK: alloca <5 x i16>, align 16
199// CHECK: [[VAR_ALIGN:%.*]] = alloca <5 x i16>
200// CHECK: [[ALIGN:%.*]] = and i32 {{%.*}}, -8
201// CHECK: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8*
202// CHECK: [[AP_NEXT:%.*]] = getelementptr i8* [[AP_ALIGN]], i32 16
203// CHECK: bitcast <5 x i16>* [[VAR_ALIGN]] to i8*
204// CHECK: call void @llvm.memcpy
205// CHECK: load <5 x i16>* [[VAR_ALIGN]]
206// APCS-GNU: varargs_vec_5s
207// APCS-GNU: alloca <5 x i16>, align 16
208// APCS-GNU: [[VAR_ALIGN:%.*]] = alloca <5 x i16>
209// APCS-GNU: [[AP_NEXT:%.*]] = getelementptr i8* {{%.*}}, i32 16
210// APCS-GNU: bitcast <5 x i16>* [[VAR_ALIGN]] to i8*
211// APCS-GNU: call void @llvm.memcpy
212// APCS-GNU: load <5 x i16>* [[VAR_ALIGN]]
213  va_list ap;
214  double sum = fixed;
215  va_start(ap, fixed);
216  __short5 c5 = va_arg(ap, __short5);
217  sum = sum + c5.x + c5.y;
218  va_end(ap);
219  return sum;
220}
221
222double test_5s(__short5 *in) {
223// CHECK: test_5s
224// CHECK: call arm_aapcscc double (i32, ...)* @varargs_vec_5s(i32 5, <4 x i32> {{%.*}})
225// APCS-GNU: test_5s
226// APCS-GNU: call double (i32, ...)* @varargs_vec_5s(i32 5, <4 x i32> {{%.*}})
227  return varargs_vec_5s(5, *in);
228}
229
230// Pass struct as varargs.
231typedef struct
232{
233  __int2 i2;
234  float f;
235} StructWithVec;
236
237double varargs_struct(int fixed, ...) {
238// CHECK: varargs_struct
239// CHECK: [[ALIGN:%.*]] = and i32 {{%.*}}, -8
240// CHECK: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8*
241// CHECK: [[AP_NEXT:%.*]] = getelementptr i8* [[AP_ALIGN]], i32 16
242// CHECK: bitcast i8* [[AP_ALIGN]] to %struct.StructWithVec*
243// APCS-GNU: varargs_struct
244// APCS-GNU: [[VAR_ALIGN:%.*]] = alloca %struct.StructWithVec
245// APCS-GNU: [[AP_NEXT:%.*]] = getelementptr i8* {{%.*}}, i32 16
246// APCS-GNU: bitcast %struct.StructWithVec* [[VAR_ALIGN]] to i8*
247// APCS-GNU: call void @llvm.memcpy
248  va_list ap;
249  double sum = fixed;
250  va_start(ap, fixed);
251  StructWithVec c3 = va_arg(ap, StructWithVec);
252  sum = sum + c3.i2.x + c3.i2.y + c3.f;
253  va_end(ap);
254  return sum;
255}
256
257double test_struct(StructWithVec* d) {
258// CHECK: test_struct
259// CHECK: call arm_aapcscc double (i32, ...)* @varargs_struct(i32 3, [2 x i64] {{%.*}})
260// APCS-GNU: test_struct
261// APCS-GNU: call double (i32, ...)* @varargs_struct(i32 3, [2 x i64] {{%.*}})
262  return varargs_struct(3, *d);
263}
264