1// REQUIRES: arm-registered-target
2// RUN: %clang_cc1 -triple armv7---eabi -target-abi aapcs -mfloat-abi hard -emit-llvm %s -o - | FileCheck %s
3
4// RUN: %clang_cc1 -triple arm64-apple-darwin9 -target-abi darwinpcs \
5// RUN:  -ffreestanding -emit-llvm -w -o - %s | FileCheck -check-prefix=CHECK64 %s
6
7// RUN: %clang_cc1 -triple arm64-linux-gnu -ffreestanding -emit-llvm -w -o - %s \
8// RUN:   | FileCheck --check-prefix=CHECK64-AAPCS %s
9typedef long long int64_t;
10typedef unsigned int uint32_t;
11
12/* This is not a homogenous aggregate - fundamental types are different */
13typedef union {
14  float       f[4];
15  uint32_t    i[4];
16} union_with_first_floats;
17union_with_first_floats g_u_f;
18
19extern void takes_union_with_first_floats(union_with_first_floats a);
20extern union_with_first_floats returns_union_with_first_floats(void);
21
22void test_union_with_first_floats(void) {
23  takes_union_with_first_floats(g_u_f);
24}
25// CHECK: declare arm_aapcs_vfpcc void @takes_union_with_first_floats({ [4 x i32] })
26
27void test_return_union_with_first_floats(void) {
28  g_u_f = returns_union_with_first_floats();
29}
30// CHECK: declare arm_aapcs_vfpcc void @returns_union_with_first_floats(%union.union_with_first_floats* sret)
31
32/* This is not a homogenous aggregate - fundamental types are different */
33typedef union {
34    uint32_t    i[4];
35    float       f[4];
36} union_with_non_first_floats;
37union_with_non_first_floats g_u_nf_f;
38
39extern void takes_union_with_non_first_floats(union_with_non_first_floats a);
40extern union_with_non_first_floats returns_union_with_non_first_floats(void);
41
42void test_union_with_non_first_floats(void) {
43  takes_union_with_non_first_floats(g_u_nf_f);
44}
45// CHECK: declare arm_aapcs_vfpcc void @takes_union_with_non_first_floats({ [4 x i32] })
46
47void test_return_union_with_non_first_floats(void) {
48  g_u_nf_f = returns_union_with_non_first_floats();
49}
50// CHECK: declare arm_aapcs_vfpcc void @returns_union_with_non_first_floats(%union.union_with_non_first_floats* sret)
51
52/* This is not a homogenous aggregate - fundamental types are different */
53typedef struct {
54  float a;
55  union_with_first_floats b;
56} struct_with_union_with_first_floats;
57struct_with_union_with_first_floats g_s_f;
58
59extern void takes_struct_with_union_with_first_floats(struct_with_union_with_first_floats a);
60extern struct_with_union_with_first_floats returns_struct_with_union_with_first_floats(void);
61
62void test_struct_with_union_with_first_floats(void) {
63  takes_struct_with_union_with_first_floats(g_s_f);
64}
65// CHECK: declare arm_aapcs_vfpcc void @takes_struct_with_union_with_first_floats({ [5 x i32] })
66
67void test_return_struct_with_union_with_first_floats(void) {
68  g_s_f = returns_struct_with_union_with_first_floats();
69}
70// CHECK: declare arm_aapcs_vfpcc void @returns_struct_with_union_with_first_floats(%struct.struct_with_union_with_first_floats* sret)
71
72/* This is not a homogenous aggregate - fundamental types are different */
73typedef struct {
74  float a;
75  union_with_non_first_floats b;
76} struct_with_union_with_non_first_floats;
77struct_with_union_with_non_first_floats g_s_nf_f;
78
79extern void takes_struct_with_union_with_non_first_floats(struct_with_union_with_non_first_floats a);
80extern struct_with_union_with_non_first_floats returns_struct_with_union_with_non_first_floats(void);
81
82void test_struct_with_union_with_non_first_floats(void) {
83  takes_struct_with_union_with_non_first_floats(g_s_nf_f);
84}
85// CHECK: declare arm_aapcs_vfpcc void @takes_struct_with_union_with_non_first_floats({ [5 x i32] })
86
87void test_return_struct_with_union_with_non_first_floats(void) {
88  g_s_nf_f = returns_struct_with_union_with_non_first_floats();
89}
90// CHECK: declare arm_aapcs_vfpcc void @returns_struct_with_union_with_non_first_floats(%struct.struct_with_union_with_non_first_floats* sret)
91
92/* Plain array is not a homogenous aggregate */
93extern void takes_array_of_floats(float a[4]);
94void test_array_of_floats(void) {
95  float a[4] = {1.0, 2.0, 3.0, 4.0};
96  takes_array_of_floats(a);
97}
98// CHECK: declare arm_aapcs_vfpcc void @takes_array_of_floats(float*)
99
100/* Struct-type homogenous aggregate */
101typedef struct {
102  float x, y, z, w;
103} struct_with_fundamental_elems;
104struct_with_fundamental_elems g_s;
105
106extern void takes_struct_with_fundamental_elems(struct_with_fundamental_elems a);
107extern struct_with_fundamental_elems returns_struct_with_fundamental_elems(void);
108
109void test_struct_with_fundamental_elems(void) {
110  takes_struct_with_fundamental_elems(g_s);
111// CHECK:  call arm_aapcs_vfpcc  void @takes_struct_with_fundamental_elems(%struct.struct_with_fundamental_elems {{.*}})
112}
113// CHECK: declare arm_aapcs_vfpcc void @takes_struct_with_fundamental_elems(%struct.struct_with_fundamental_elems)
114
115void test_return_struct_with_fundamental_elems(void) {
116  g_s = returns_struct_with_fundamental_elems();
117// CHECK: call arm_aapcs_vfpcc  %struct.struct_with_fundamental_elems @returns_struct_with_fundamental_elems()
118}
119// CHECK: declare arm_aapcs_vfpcc %struct.struct_with_fundamental_elems @returns_struct_with_fundamental_elems()
120
121/* Array-type homogenous aggregate */
122typedef struct {
123  float xyzw[4];
124} struct_with_array;
125struct_with_array g_s_a;
126
127extern void takes_struct_with_array(struct_with_array a);
128extern struct_with_array returns_struct_with_array(void);
129
130void test_struct_with_array(void) {
131  takes_struct_with_array(g_s_a);
132// CHECK:   call arm_aapcs_vfpcc  void @takes_struct_with_array(%struct.struct_with_array {{.*}})
133}
134// CHECK: declare arm_aapcs_vfpcc void @takes_struct_with_array(%struct.struct_with_array)
135
136void test_return_struct_with_array(void) {
137  g_s_a = returns_struct_with_array();
138// CHECK:   call arm_aapcs_vfpcc  %struct.struct_with_array @returns_struct_with_array()
139}
140// CHECK: declare arm_aapcs_vfpcc %struct.struct_with_array @returns_struct_with_array()
141
142/* This union is a homogenous aggregate. Check that it's passed properly */
143typedef union {
144  struct_with_fundamental_elems xyzw;
145  float a[3];
146} union_with_struct_with_fundamental_elems;
147union_with_struct_with_fundamental_elems g_u_s_fe;
148
149extern void takes_union_with_struct_with_fundamental_elems(union_with_struct_with_fundamental_elems a);
150extern union_with_struct_with_fundamental_elems returns_union_with_struct_with_fundamental_elems(void);
151
152void test_union_with_struct_with_fundamental_elems(void) {
153  takes_union_with_struct_with_fundamental_elems(g_u_s_fe);
154// CHECK: call arm_aapcs_vfpcc  void @takes_union_with_struct_with_fundamental_elems(%union.union_with_struct_with_fundamental_elems {{.*}})
155}
156// CHECK: declare arm_aapcs_vfpcc void @takes_union_with_struct_with_fundamental_elems(%union.union_with_struct_with_fundamental_elems)
157
158void test_return_union_with_struct_with_fundamental_elems(void) {
159  g_u_s_fe = returns_union_with_struct_with_fundamental_elems();
160// CHECK: call arm_aapcs_vfpcc  %union.union_with_struct_with_fundamental_elems @returns_union_with_struct_with_fundamental_elems()
161}
162// CHECK: declare arm_aapcs_vfpcc %union.union_with_struct_with_fundamental_elems @returns_union_with_struct_with_fundamental_elems()
163
164// Make sure HAs that can be partially fit into VFP registers will be allocated
165// on stack and that later VFP candidates will go on stack as well.
166typedef struct {
167  double x;
168  double a2;
169  double a3;
170  double a4;
171} struct_of_four_doubles;
172extern void takes_struct_of_four_doubles(double a, struct_of_four_doubles b, struct_of_four_doubles c, double d);
173struct_of_four_doubles g_s4d;
174
175void test_struct_of_four_doubles(void) {
176// CHECK: test_struct_of_four_doubles
177// CHECK: call arm_aapcs_vfpcc void @takes_struct_of_four_doubles(double {{.*}}, %struct.struct_of_four_doubles {{.*}}, %struct.struct_of_four_doubles {{.*}}, double {{.*}})
178// CHECK64: test_struct_of_four_doubles
179// CHECK64: call void @takes_struct_of_four_doubles(double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, [3 x float] undef, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}})
180// CHECK64-AAPCS: test_struct_of_four_doubles
181// CHECK64-AAPCS: call void @takes_struct_of_four_doubles(double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, [3 x float] undef, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}})
182  takes_struct_of_four_doubles(3.0, g_s4d, g_s4d, 4.0);
183}
184
185extern void takes_struct_of_four_doubles_variadic(double a, struct_of_four_doubles b, struct_of_four_doubles c, double d, ...);
186
187void test_struct_of_four_doubles_variadic(void) {
188// CHECK: test_struct_of_four_doubles_variadic
189// CHECK: call arm_aapcs_vfpcc void (double, { [4 x i64] }, { [4 x i64] }, double, ...)* @takes_struct_of_four_doubles_variadic(double {{.*}}, { [4 x i64] } {{.*}}, { [4 x i64] } {{.*}}, double {{.*}})
190  takes_struct_of_four_doubles_variadic(3.0, g_s4d, g_s4d, 4.0);
191}
192
193extern void takes_struct_with_backfill(float f1, double a, float f2, struct_of_four_doubles b, struct_of_four_doubles c, double d);
194void test_struct_with_backfill(void) {
195// CHECK: test_struct_with_backfill
196// CHECK: call arm_aapcs_vfpcc void @takes_struct_with_backfill(float {{.*}}, double {{.*}}, float {{.*}}, %struct.struct_of_four_doubles {{.*}}, %struct.struct_of_four_doubles {{.*}}, double {{.*}})
197  takes_struct_with_backfill(3.0, 3.1, 3.2, g_s4d, g_s4d, 4.0);
198}
199
200typedef __attribute__(( ext_vector_type(8) )) char __char8;
201typedef __attribute__(( ext_vector_type(4) ))  short __short4;
202typedef struct {
203  __char8  a1;
204  __short4 a2;
205  __char8  a3;
206  __short4 a4;
207} struct_of_vecs;
208extern void takes_struct_of_vecs(double a, struct_of_vecs b, struct_of_vecs c, double d);
209struct_of_vecs g_vec;
210
211void test_struct_of_vecs(void) {
212// CHECK: test_struct_of_vecs
213// CHECK: call arm_aapcs_vfpcc void @takes_struct_of_vecs(double {{.*}}, %struct.struct_of_vecs {{.*}}, %struct.struct_of_vecs {{.*}}, double {{.*}})
214// CHECK64: test_struct_of_vecs
215// CHECK64: call void @takes_struct_of_vecs(double {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, [3 x float] undef, <8 x i8> {{.*}}, <4 x i16> {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, double {{.*}})
216// CHECK64-AAPCS: test_struct_of_vecs
217// CHECK64-AAPCS: call void @takes_struct_of_vecs(double {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, [3 x float] undef, <8 x i8> {{.*}}, <4 x i16> {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, double {{.*}})
218  takes_struct_of_vecs(3.0, g_vec, g_vec, 4.0);
219}
220
221typedef struct {
222  double a;
223  long double b;
224} struct_of_double_and_long_double;
225struct_of_double_and_long_double g_dld;
226
227struct_of_double_and_long_double test_struct_of_double_and_long_double(void) {
228  return g_dld;
229}
230// CHECK: define arm_aapcs_vfpcc %struct.struct_of_double_and_long_double @test_struct_of_double_and_long_double()
231
232// FIXME: Tests necessary:
233//         - Vectors
234//         - C++ stuff
235