1 // RUN: %clang_cc1 -triple arm-none-eabi -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-LE %s
2 // RUN: %clang_cc1 -triple armeb-none-eabi -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-BE %s
3 
4 #include <stdarg.h>
5 
6 // Obviously there's more than one way to implement va_arg. This test should at
7 // least prevent unintentional regressions caused by refactoring.
8 
9 va_list the_list;
10 
simple_int(void)11 int simple_int(void) {
12 // CHECK-LABEL: define i32 @simple_int
13   return va_arg(the_list, int);
14 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
15 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 4
16 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
17 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR]] to i32*
18 // CHECK: [[RESULT:%[a-z0-9._]+]] = load i32, i32* [[ADDR]]
19 // CHECK: ret i32 [[RESULT]]
20 }
21 
22 struct bigstruct {
23   int a[10];
24 };
25 
simple_struct(void)26 struct bigstruct simple_struct(void) {
27 // CHECK-LABEL: define void @simple_struct(%struct.bigstruct* noalias sret align 4 %agg.result)
28   return va_arg(the_list, struct bigstruct);
29 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
30 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 40
31 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
32 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR]] to %struct.bigstruct*
33 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.bigstruct* %agg.result to i8*
34 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.bigstruct* [[ADDR]] to i8*
35 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 [[DEST_ADDR]], i8* align 4 [[SRC_ADDR]], i32 40, i1 false)
36 // CHECK: ret void
37 }
38 
39 struct aligned_bigstruct {
40   float a;
41   long double b;
42 };
43 
simple_aligned_struct(void)44 struct aligned_bigstruct simple_aligned_struct(void) {
45 // CHECK-LABEL: define void @simple_aligned_struct(%struct.aligned_bigstruct* noalias sret align 8 %agg.result)
46   return va_arg(the_list, struct aligned_bigstruct);
47 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
48 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32
49 // CHECK: [[CUR_INT_ADD:%[a-z0-9._]+]] = add i32 [[CUR_INT]], 7
50 // CHECK: [[CUR_INT_ALIGNED:%[a-z0-9._]+]] = and i32 [[CUR_INT_ADD]], -8
51 // CHECK: [[CUR_ALIGNED:%[a-z0-9._]+]] = inttoptr i32 [[CUR_INT_ALIGNED]] to i8*
52 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR_ALIGNED]], i32 16
53 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
54 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR_ALIGNED]] to %struct.aligned_bigstruct*
55 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.aligned_bigstruct* %agg.result to i8*
56 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.aligned_bigstruct* [[ADDR]] to i8*
57 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 [[DEST_ADDR]], i8* align 8 [[SRC_ADDR]], i32 16, i1 false)
58 // CHECK: ret void
59 }
60 
simple_double(void)61 double simple_double(void) {
62 // CHECK-LABEL: define double @simple_double
63   return va_arg(the_list, double);
64 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
65 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32
66 // CHECK: [[CUR_INT_ADD:%[a-z0-9._]+]] = add i32 [[CUR_INT]], 7
67 // CHECK: [[CUR_INT_ALIGNED:%[a-z0-9._]+]] = and i32 [[CUR_INT_ADD]], -8
68 // CHECK: [[CUR_ALIGNED:%[a-z0-9._]+]] = inttoptr i32 [[CUR_INT_ALIGNED]] to i8*
69 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR_ALIGNED]], i32 8
70 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
71 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR_ALIGNED]] to double*
72 // CHECK: [[RESULT:%[a-z0-9._]+]] = load double, double* [[ADDR]]
73 // CHECK: ret double [[RESULT]]
74 }
75 
76 struct hfa {
77   float a, b;
78 };
79 
simple_hfa(void)80 struct hfa simple_hfa(void) {
81 // CHECK-LABEL: define void @simple_hfa(%struct.hfa* noalias sret align 4 %agg.result)
82   return va_arg(the_list, struct hfa);
83 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
84 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 8
85 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
86 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR]] to %struct.hfa*
87 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.hfa* %agg.result to i8*
88 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.hfa* [[ADDR]] to i8*
89 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 [[DEST_ADDR]], i8* align 4 [[SRC_ADDR]], i32 8, i1 false)
90 // CHECK: ret void
91 }
92 
93 // Over and under alignment on fundamental types has no effect on parameter
94 // passing, so the code generated for va_arg should be the same as for
95 // non-aligned fundamental types.
96 
97 typedef int underaligned_int __attribute__((packed,aligned(2)));
underaligned_int_test()98 underaligned_int underaligned_int_test() {
99 // CHECK-LABEL: define i32 @underaligned_int_test()
100   return va_arg(the_list, underaligned_int);
101 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
102 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 4
103 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
104 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR]] to i32*
105 // CHECK: [[RESULT:%[a-z0-9._]+]] = load i32, i32* [[ADDR]]
106 // CHECK: ret i32 [[RESULT]]
107 }
108 
109 typedef int overaligned_int __attribute__((aligned(32)));
overaligned_int_test()110 overaligned_int overaligned_int_test() {
111 // CHECK-LABEL: define i32 @overaligned_int_test()
112   return va_arg(the_list, overaligned_int);
113 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
114 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 4
115 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
116 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR]] to i32*
117 // CHECK: [[RESULT:%[a-z0-9._]+]] = load i32, i32* [[ADDR]]
118 // CHECK: ret i32 [[RESULT]]
119 }
120 
121 typedef long long underaligned_long_long  __attribute__((packed,aligned(2)));
underaligned_long_long_test()122 underaligned_long_long underaligned_long_long_test() {
123 // CHECK-LABEL: define i64 @underaligned_long_long_test()
124   return va_arg(the_list, underaligned_long_long);
125 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
126 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32
127 // CHECK: [[CUR_INT_ADD:%[a-z0-9._]+]] = add i32 [[CUR_INT]], 7
128 // CHECK: [[CUR_INT_ALIGNED:%[a-z0-9._]+]] = and i32 [[CUR_INT_ADD]], -8
129 // CHECK: [[CUR_ALIGNED:%[a-z0-9._]+]] = inttoptr i32 [[CUR_INT_ALIGNED]] to i8*
130 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR_ALIGNED]], i32 8
131 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
132 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR_ALIGNED]] to i64*
133 // CHECK: [[RESULT:%[a-z0-9._]+]] = load i64, i64* [[ADDR]]
134 // CHECK: ret i64 [[RESULT]]
135 }
136 
137 typedef long long overaligned_long_long  __attribute__((aligned(32)));
overaligned_long_long_test()138 overaligned_long_long overaligned_long_long_test() {
139 // CHECK-LABEL: define i64 @overaligned_long_long_test()
140   return va_arg(the_list, overaligned_long_long);
141 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
142 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32
143 // CHECK: [[CUR_INT_ADD:%[a-z0-9._]+]] = add i32 [[CUR_INT]], 7
144 // CHECK: [[CUR_INT_ALIGNED:%[a-z0-9._]+]] = and i32 [[CUR_INT_ADD]], -8
145 // CHECK: [[CUR_ALIGNED:%[a-z0-9._]+]] = inttoptr i32 [[CUR_INT_ALIGNED]] to i8*
146 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR_ALIGNED]], i32 8
147 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
148 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR_ALIGNED]] to i64*
149 // CHECK: [[RESULT:%[a-z0-9._]+]] = load i64, i64* [[ADDR]]
150 // CHECK: ret i64 [[RESULT]]
151 }
152 
153 // The way that attributes applied to a struct change parameter passing is a
154 // little strange, in that the alignment due to attributes is used when
155 // calculating the size of the struct, but the alignment is based only on the
156 // alignment of the members (which can be affected by attributes). What this
157 // means is:
158 //  * The only effect of the aligned attribute on a struct is to increase its
159 //    size if the alignment is greater than the member alignment.
160 //  * The packed attribute is considered as applying to the members, so it will
161 //    affect the alignment.
162 // Additionally the alignment can't go below 4 or above 8, so it's only
163 // long long and double that can be affected by a change in alignment.
164 
165 typedef struct __attribute__((packed,aligned(2))) {
166   int val;
167 } underaligned_int_struct;
underaligned_int_struct_test()168 underaligned_int_struct underaligned_int_struct_test() {
169 // CHECK-LABEL: define i32 @underaligned_int_struct_test()
170   return va_arg(the_list, underaligned_int_struct);
171 // CHECK: [[RETVAL:%[a-z0-9._]+]] = alloca %struct.underaligned_int_struct, align 2
172 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
173 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 4
174 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
175 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR]] to %struct.underaligned_int_struct*
176 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.underaligned_int_struct* [[RETVAL]] to i8*
177 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.underaligned_int_struct* [[ADDR]] to i8*
178 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 2 [[DEST_ADDR]], i8* align 4 [[SRC_ADDR]], i32 4, i1 false)
179 // CHECK: [[COERCE:%[a-z0-9._]+]] = getelementptr inbounds %struct.underaligned_int_struct, %struct.underaligned_int_struct* [[RETVAL]], i32 0, i32 0
180 // CHECK: [[RESULT:%[a-z0-9._]+]] = load i32, i32* [[COERCE]]
181 // CHECK: ret i32 [[RESULT]]
182 }
183 
184 typedef struct __attribute__((aligned(16))) {
185   int val;
186 } overaligned_int_struct;
overaligned_int_struct_test()187 overaligned_int_struct overaligned_int_struct_test() {
188 // CHECK-LABEL: define void @overaligned_int_struct_test(%struct.overaligned_int_struct* noalias sret align 16 %agg.result)
189   return va_arg(the_list, overaligned_int_struct);
190 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
191 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 16
192 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
193 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR]] to %struct.overaligned_int_struct*
194 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.overaligned_int_struct* %agg.result to i8*
195 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.overaligned_int_struct* [[ADDR]] to i8*
196 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 16 [[DEST_ADDR]], i8* align 4 [[SRC_ADDR]], i32 16, i1 false)
197 // CHECK: ret void
198 }
199 
200 typedef struct __attribute__((packed,aligned(2))) {
201   long long val;
202 } underaligned_long_long_struct;
underaligned_long_long_struct_test()203 underaligned_long_long_struct underaligned_long_long_struct_test() {
204 // CHECK-LABEL: define void @underaligned_long_long_struct_test(%struct.underaligned_long_long_struct* noalias sret align 2 %agg.result)
205   return va_arg(the_list, underaligned_long_long_struct);
206 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
207 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 8
208 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
209 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR]] to %struct.underaligned_long_long_struct*
210 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.underaligned_long_long_struct* %agg.result to i8*
211 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.underaligned_long_long_struct* [[ADDR]] to i8*
212 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 2 [[DEST_ADDR]], i8* align 4 [[SRC_ADDR]], i32 8, i1 false)
213 // CHECK: ret void
214 }
215 
216 typedef struct __attribute__((aligned(16))) {
217   long long val;
218 } overaligned_long_long_struct;
overaligned_long_long_struct_test()219 overaligned_long_long_struct overaligned_long_long_struct_test() {
220 // CHECK-LABEL: define void @overaligned_long_long_struct_test(%struct.overaligned_long_long_struct* noalias sret align 16 %agg.result)
221   return va_arg(the_list, overaligned_long_long_struct);
222 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
223 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32
224 // CHECK: [[CUR_INT_ADD:%[a-z0-9._]+]] = add i32 [[CUR_INT]], 7
225 // CHECK: [[CUR_INT_ALIGNED:%[a-z0-9._]+]] = and i32 [[CUR_INT_ADD]], -8
226 // CHECK: [[CUR_ALIGNED:%[a-z0-9._]+]] = inttoptr i32 [[CUR_INT_ALIGNED]] to i8*
227 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR_ALIGNED]], i32 16
228 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
229 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR_ALIGNED]] to %struct.overaligned_long_long_struct*
230 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.overaligned_long_long_struct* %agg.result to i8*
231 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.overaligned_long_long_struct* [[ADDR]] to i8*
232 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 16 [[DEST_ADDR]], i8* align 8 [[SRC_ADDR]], i32 16, i1 false)
233 // CHECK: ret void
234 }
235 
236 // Overaligning or underaligning a struct member changes both its alignment and
237 // size when passed as an argument.
238 
239 typedef struct {
240   int val __attribute__((packed,aligned(2)));
241 } underaligned_int_struct_member;
underaligned_int_struct_member_test()242 underaligned_int_struct_member underaligned_int_struct_member_test() {
243 // CHECK-LABEL: define i32 @underaligned_int_struct_member_test()
244   return va_arg(the_list, underaligned_int_struct_member);
245 // CHECK: [[RETVAL:%[a-z0-9._]+]] = alloca %struct.underaligned_int_struct_member, align 2
246 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
247 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 4
248 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
249 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR]] to %struct.underaligned_int_struct_member*
250 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.underaligned_int_struct_member* [[RETVAL]] to i8*
251 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.underaligned_int_struct_member* [[ADDR]] to i8*
252 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 2 [[DEST_ADDR]], i8* align 4 [[SRC_ADDR]], i32 4, i1 false)
253 // CHECK: [[COERCE:%[a-z0-9._]+]] = getelementptr inbounds %struct.underaligned_int_struct_member, %struct.underaligned_int_struct_member* [[RETVAL]], i32 0, i32 0
254 // CHECK: [[RESULT:%[a-z0-9._]+]] = load i32, i32* [[COERCE]]
255 // CHECK: ret i32 [[RESULT]]
256 }
257 
258 typedef struct {
259   int val __attribute__((aligned(16)));
260 } overaligned_int_struct_member;
overaligned_int_struct_member_test()261 overaligned_int_struct_member overaligned_int_struct_member_test() {
262 // CHECK-LABEL: define void @overaligned_int_struct_member_test(%struct.overaligned_int_struct_member* noalias sret align 16 %agg.result)
263   return va_arg(the_list, overaligned_int_struct_member);
264 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
265 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32
266 // CHECK: [[CUR_INT_ADD:%[a-z0-9._]+]] = add i32 [[CUR_INT]], 7
267 // CHECK: [[CUR_INT_ALIGNED:%[a-z0-9._]+]] = and i32 [[CUR_INT_ADD]], -8
268 // CHECK: [[CUR_ALIGNED:%[a-z0-9._]+]] = inttoptr i32 [[CUR_INT_ALIGNED]] to i8*
269 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR_ALIGNED]], i32 16
270 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
271 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR_ALIGNED]] to %struct.overaligned_int_struct_member*
272 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.overaligned_int_struct_member* %agg.result to i8*
273 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.overaligned_int_struct_member* [[ADDR]] to i8*
274 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 16 [[DEST_ADDR]], i8* align 8 [[SRC_ADDR]], i32 16, i1 false)
275 // CHECK: ret void
276 }
277 
278 typedef struct {
279   long long val __attribute__((packed,aligned(2)));
280 } underaligned_long_long_struct_member;
underaligned_long_long_struct_member_test()281 underaligned_long_long_struct_member underaligned_long_long_struct_member_test() {
282 // CHECK-LABEL: define void @underaligned_long_long_struct_member_test(%struct.underaligned_long_long_struct_member* noalias sret align 2 %agg.result)
283   return va_arg(the_list, underaligned_long_long_struct_member);
284 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
285 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 8
286 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
287 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR]] to %struct.underaligned_long_long_struct_member*
288 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.underaligned_long_long_struct_member* %agg.result to i8*
289 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.underaligned_long_long_struct_member* [[ADDR]] to i8*
290 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 2 [[DEST_ADDR]], i8* align 4 [[SRC_ADDR]], i32 8, i1 false)
291 // CHECK: ret void
292 }
293 
294 typedef struct {
295   long long val __attribute__((aligned(16)));
296 } overaligned_long_long_struct_member;
overaligned_long_long_struct_member_test()297 overaligned_long_long_struct_member overaligned_long_long_struct_member_test() {
298 // CHECK-LABEL: define void @overaligned_long_long_struct_member_test(%struct.overaligned_long_long_struct_member* noalias sret align 16 %agg.result)
299   return va_arg(the_list, overaligned_long_long_struct_member);
300 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
301 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32
302 // CHECK: [[CUR_INT_ADD:%[a-z0-9._]+]] = add i32 [[CUR_INT]], 7
303 // CHECK: [[CUR_INT_ALIGNED:%[a-z0-9._]+]] = and i32 [[CUR_INT_ADD]], -8
304 // CHECK: [[CUR_ALIGNED:%[a-z0-9._]+]] = inttoptr i32 [[CUR_INT_ALIGNED]] to i8*
305 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR_ALIGNED]], i32 16
306 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4
307 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR_ALIGNED]] to %struct.overaligned_long_long_struct_member*
308 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.overaligned_long_long_struct_member* %agg.result to i8*
309 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.overaligned_long_long_struct_member* [[ADDR]] to i8*
310 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 16 [[DEST_ADDR]], i8* align 8 [[SRC_ADDR]], i32 16, i1 false)
311 // CHECK: ret void
312 }
313 
check_start(int n,...)314 void check_start(int n, ...) {
315 // CHECK-LABEL: define void @check_start(i32 %n, ...)
316 
317   va_list the_list;
318   va_start(the_list, n);
319 // CHECK: [[THE_LIST:%[a-z0-9._]+]] = alloca %struct.__va_list
320 // CHECK: [[VOIDP_THE_LIST:%[a-z0-9._]+]] = bitcast %struct.__va_list* [[THE_LIST]] to i8*
321 // CHECK: call void @llvm.va_start.p0i8(i8* [[VOIDP_THE_LIST]])
322 }
323