1 // RUN: %clang_cc1 -triple arm-none-eabi -emit-llvm -o - %s | FileCheck %s
2 // RUN: %clang_cc1 -triple armeb-none-eabi -emit-llvm -o - %s | FileCheck %s
6 // Obviously there's more than one way to implement va_arg. This test should at
7 // least prevent unintentional regressions caused by refactoring.
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 ptr, ptr @the_list, align 4
15 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, ptr [[CUR]], i32 4
16 // CHECK: store ptr [[NEXT]], ptr @the_list, align 4
17 // CHECK: [[RESULT:%[a-z0-9._]+]] = load i32, ptr [[CUR]]
18 // CHECK: ret i32 [[RESULT]]
25 struct bigstruct
simple_struct(void) {
26 // CHECK-LABEL: define{{.*}} void @simple_struct(ptr noalias sret(%struct.bigstruct) align 4 %agg.result)
27 return va_arg(the_list
, struct bigstruct
);
28 // CHECK: [[CUR:%[a-z0-9._]+]] = load ptr, ptr @the_list, align 4
29 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, ptr [[CUR]], i32 40
30 // CHECK: store ptr [[NEXT]], ptr @the_list, align 4
31 // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %agg.result, ptr align 4 [[CUR]], i32 40, i1 false)
35 struct aligned_bigstruct
{
40 struct aligned_bigstruct
simple_aligned_struct(void) {
41 // CHECK-LABEL: define{{.*}} void @simple_aligned_struct(ptr noalias sret(%struct.aligned_bigstruct) align 8 %agg.result)
42 return va_arg(the_list
, struct aligned_bigstruct
);
43 // CHECK: [[CUR:%[a-z0-9._]+]] = load ptr, ptr @the_list, align 4
44 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint ptr [[CUR]] to i32
45 // CHECK: [[CUR_INT_ADD:%[a-z0-9._]+]] = add i32 [[CUR_INT]], 7
46 // CHECK: [[CUR_INT_ALIGNED:%[a-z0-9._]+]] = and i32 [[CUR_INT_ADD]], -8
47 // CHECK: [[CUR_ALIGNED:%[a-z0-9._]+]] = inttoptr i32 [[CUR_INT_ALIGNED]] to ptr
48 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, ptr [[CUR_ALIGNED]], i32 16
49 // CHECK: store ptr [[NEXT]], ptr @the_list, align 4
50 // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 8 %agg.result, ptr align 8 [[CUR_ALIGNED]], i32 16, i1 false)
54 double simple_double(void) {
55 // CHECK-LABEL: define{{.*}} double @simple_double
56 return va_arg(the_list
, double);
57 // CHECK: [[CUR:%[a-z0-9._]+]] = load ptr, ptr @the_list, align 4
58 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint ptr [[CUR]] to i32
59 // CHECK: [[CUR_INT_ADD:%[a-z0-9._]+]] = add i32 [[CUR_INT]], 7
60 // CHECK: [[CUR_INT_ALIGNED:%[a-z0-9._]+]] = and i32 [[CUR_INT_ADD]], -8
61 // CHECK: [[CUR_ALIGNED:%[a-z0-9._]+]] = inttoptr i32 [[CUR_INT_ALIGNED]] to ptr
62 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, ptr [[CUR_ALIGNED]], i32 8
63 // CHECK: store ptr [[NEXT]], ptr @the_list, align 4
64 // CHECK: [[RESULT:%[a-z0-9._]+]] = load double, ptr [[CUR_ALIGNED]]
65 // CHECK: ret double [[RESULT]]
72 struct hfa
simple_hfa(void) {
73 // CHECK-LABEL: define{{.*}} void @simple_hfa(ptr noalias sret(%struct.hfa) align 4 %agg.result)
74 return va_arg(the_list
, struct hfa
);
75 // CHECK: [[CUR:%[a-z0-9._]+]] = load ptr, ptr @the_list, align 4
76 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, ptr [[CUR]], i32 8
77 // CHECK: store ptr [[NEXT]], ptr @the_list, align 4
78 // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 %agg.result, ptr align 4 [[CUR]], i32 8, i1 false)
82 // Over and under alignment on fundamental types has no effect on parameter
83 // passing, so the code generated for va_arg should be the same as for
84 // non-aligned fundamental types.
86 typedef int underaligned_int
__attribute__((packed
,aligned(2)));
87 underaligned_int
underaligned_int_test(void) {
88 // CHECK-LABEL: define{{.*}} i32 @underaligned_int_test()
89 return va_arg(the_list
, underaligned_int
);
90 // CHECK: [[CUR:%[a-z0-9._]+]] = load ptr, ptr @the_list, align 4
91 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, ptr [[CUR]], i32 4
92 // CHECK: store ptr [[NEXT]], ptr @the_list, align 4
93 // CHECK: [[RESULT:%[a-z0-9._]+]] = load i32, ptr [[CUR]]
94 // CHECK: ret i32 [[RESULT]]
97 typedef int overaligned_int
__attribute__((aligned(32)));
98 overaligned_int
overaligned_int_test(void) {
99 // CHECK-LABEL: define{{.*}} i32 @overaligned_int_test()
100 return va_arg(the_list
, overaligned_int
);
101 // CHECK: [[CUR:%[a-z0-9._]+]] = load ptr, ptr @the_list, align 4
102 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, ptr [[CUR]], i32 4
103 // CHECK: store ptr [[NEXT]], ptr @the_list, align 4
104 // CHECK: [[RESULT:%[a-z0-9._]+]] = load i32, ptr [[CUR]]
105 // CHECK: ret i32 [[RESULT]]
108 typedef long long underaligned_long_long
__attribute__((packed
,aligned(2)));
109 underaligned_long_long
underaligned_long_long_test(void) {
110 // CHECK-LABEL: define{{.*}} i64 @underaligned_long_long_test()
111 return va_arg(the_list
, underaligned_long_long
);
112 // CHECK: [[CUR:%[a-z0-9._]+]] = load ptr, ptr @the_list, align 4
113 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint ptr [[CUR]] to i32
114 // CHECK: [[CUR_INT_ADD:%[a-z0-9._]+]] = add i32 [[CUR_INT]], 7
115 // CHECK: [[CUR_INT_ALIGNED:%[a-z0-9._]+]] = and i32 [[CUR_INT_ADD]], -8
116 // CHECK: [[CUR_ALIGNED:%[a-z0-9._]+]] = inttoptr i32 [[CUR_INT_ALIGNED]] to ptr
117 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, ptr [[CUR_ALIGNED]], i32 8
118 // CHECK: store ptr [[NEXT]], ptr @the_list, align 4
119 // CHECK: [[RESULT:%[a-z0-9._]+]] = load i64, ptr [[CUR_ALIGNED]]
120 // CHECK: ret i64 [[RESULT]]
123 typedef long long overaligned_long_long
__attribute__((aligned(32)));
124 overaligned_long_long
overaligned_long_long_test(void) {
125 // CHECK-LABEL: define{{.*}} i64 @overaligned_long_long_test()
126 return va_arg(the_list
, overaligned_long_long
);
127 // CHECK: [[CUR:%[a-z0-9._]+]] = load ptr, ptr @the_list, align 4
128 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint ptr [[CUR]] to i32
129 // CHECK: [[CUR_INT_ADD:%[a-z0-9._]+]] = add i32 [[CUR_INT]], 7
130 // CHECK: [[CUR_INT_ALIGNED:%[a-z0-9._]+]] = and i32 [[CUR_INT_ADD]], -8
131 // CHECK: [[CUR_ALIGNED:%[a-z0-9._]+]] = inttoptr i32 [[CUR_INT_ALIGNED]] to ptr
132 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, ptr [[CUR_ALIGNED]], i32 8
133 // CHECK: store ptr [[NEXT]], ptr @the_list, align 4
134 // CHECK: [[RESULT:%[a-z0-9._]+]] = load i64, ptr [[CUR_ALIGNED]]
135 // CHECK: ret i64 [[RESULT]]
138 // The way that attributes applied to a struct change parameter passing is a
139 // little strange, in that the alignment due to attributes is used when
140 // calculating the size of the struct, but the alignment is based only on the
141 // alignment of the members (which can be affected by attributes). What this
143 // * The only effect of the aligned attribute on a struct is to increase its
144 // size if the alignment is greater than the member alignment.
145 // * The packed attribute is considered as applying to the members, so it will
146 // affect the alignment.
147 // Additionally the alignment can't go below 4 or above 8, so it's only
148 // long long and double that can be affected by a change in alignment.
150 typedef struct __attribute__((packed
,aligned(2))) {
152 } underaligned_int_struct
;
153 underaligned_int_struct
underaligned_int_struct_test(void) {
154 // CHECK-LABEL: define{{.*}} i32 @underaligned_int_struct_test()
155 return va_arg(the_list
, underaligned_int_struct
);
156 // CHECK: [[RETVAL:%[a-z0-9._]+]] = alloca %struct.underaligned_int_struct, align 2
157 // CHECK: [[CUR:%[a-z0-9._]+]] = load ptr, ptr @the_list, align 4
158 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, ptr [[CUR]], i32 4
159 // CHECK: store ptr [[NEXT]], ptr @the_list, align 4
160 // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 2 [[RETVAL]], ptr align 4 [[CUR]], i32 4, i1 false)
161 // CHECK: [[COERCE:%[a-z0-9._]+]] = getelementptr inbounds %struct.underaligned_int_struct, ptr [[RETVAL]], i32 0, i32 0
162 // CHECK: [[RESULT:%[a-z0-9._]+]] = load i32, ptr [[COERCE]]
163 // CHECK: ret i32 [[RESULT]]
166 typedef struct __attribute__((aligned(16))) {
168 } overaligned_int_struct
;
169 overaligned_int_struct
overaligned_int_struct_test(void) {
170 // CHECK-LABEL: define{{.*}} void @overaligned_int_struct_test(ptr noalias sret(%struct.overaligned_int_struct) align 16 %agg.result)
171 return va_arg(the_list
, overaligned_int_struct
);
172 // CHECK: [[CUR:%[a-z0-9._]+]] = load ptr, ptr @the_list, align 4
173 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, ptr [[CUR]], i32 16
174 // CHECK: store ptr [[NEXT]], ptr @the_list, align 4
175 // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 16 %agg.result, ptr align 4 [[CUR]], i32 16, i1 false)
179 typedef struct __attribute__((packed
,aligned(2))) {
181 } underaligned_long_long_struct
;
182 underaligned_long_long_struct
underaligned_long_long_struct_test(void) {
183 // CHECK-LABEL: define{{.*}} void @underaligned_long_long_struct_test(ptr noalias sret(%struct.underaligned_long_long_struct) align 2 %agg.result)
184 return va_arg(the_list
, underaligned_long_long_struct
);
185 // CHECK: [[CUR:%[a-z0-9._]+]] = load ptr, ptr @the_list, align 4
186 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, ptr [[CUR]], i32 8
187 // CHECK: store ptr [[NEXT]], ptr @the_list, align 4
188 // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 2 %agg.result, ptr align 4 [[CUR]], i32 8, i1 false)
192 typedef struct __attribute__((aligned(16))) {
194 } overaligned_long_long_struct
;
195 overaligned_long_long_struct
overaligned_long_long_struct_test(void) {
196 // CHECK-LABEL: define{{.*}} void @overaligned_long_long_struct_test(ptr noalias sret(%struct.overaligned_long_long_struct) align 16 %agg.result)
197 return va_arg(the_list
, overaligned_long_long_struct
);
198 // CHECK: [[CUR:%[a-z0-9._]+]] = load ptr, ptr @the_list, align 4
199 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint ptr [[CUR]] to i32
200 // CHECK: [[CUR_INT_ADD:%[a-z0-9._]+]] = add i32 [[CUR_INT]], 7
201 // CHECK: [[CUR_INT_ALIGNED:%[a-z0-9._]+]] = and i32 [[CUR_INT_ADD]], -8
202 // CHECK: [[CUR_ALIGNED:%[a-z0-9._]+]] = inttoptr i32 [[CUR_INT_ALIGNED]] to ptr
203 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, ptr [[CUR_ALIGNED]], i32 16
204 // CHECK: store ptr [[NEXT]], ptr @the_list, align 4
205 // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 16 %agg.result, ptr align 8 [[CUR_ALIGNED]], i32 16, i1 false)
209 // Overaligning or underaligning a struct member changes both its alignment and
210 // size when passed as an argument.
213 int val
__attribute__((packed
,aligned(2)));
214 } underaligned_int_struct_member
;
215 underaligned_int_struct_member
underaligned_int_struct_member_test(void) {
216 // CHECK-LABEL: define{{.*}} i32 @underaligned_int_struct_member_test()
217 return va_arg(the_list
, underaligned_int_struct_member
);
218 // CHECK: [[RETVAL:%[a-z0-9._]+]] = alloca %struct.underaligned_int_struct_member, align 2
219 // CHECK: [[CUR:%[a-z0-9._]+]] = load ptr, ptr @the_list, align 4
220 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, ptr [[CUR]], i32 4
221 // CHECK: store ptr [[NEXT]], ptr @the_list, align 4
222 // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 2 [[RETVAL]], ptr align 4 [[CUR]], i32 4, i1 false)
223 // CHECK: [[COERCE:%[a-z0-9._]+]] = getelementptr inbounds %struct.underaligned_int_struct_member, ptr [[RETVAL]], i32 0, i32 0
224 // CHECK: [[RESULT:%[a-z0-9._]+]] = load i32, ptr [[COERCE]]
225 // CHECK: ret i32 [[RESULT]]
229 int val
__attribute__((aligned(16)));
230 } overaligned_int_struct_member
;
231 overaligned_int_struct_member
overaligned_int_struct_member_test(void) {
232 // CHECK-LABEL: define{{.*}} void @overaligned_int_struct_member_test(ptr noalias sret(%struct.overaligned_int_struct_member) align 16 %agg.result)
233 return va_arg(the_list
, overaligned_int_struct_member
);
234 // CHECK: [[CUR:%[a-z0-9._]+]] = load ptr, ptr @the_list, align 4
235 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint ptr [[CUR]] to i32
236 // CHECK: [[CUR_INT_ADD:%[a-z0-9._]+]] = add i32 [[CUR_INT]], 7
237 // CHECK: [[CUR_INT_ALIGNED:%[a-z0-9._]+]] = and i32 [[CUR_INT_ADD]], -8
238 // CHECK: [[CUR_ALIGNED:%[a-z0-9._]+]] = inttoptr i32 [[CUR_INT_ALIGNED]] to ptr
239 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, ptr [[CUR_ALIGNED]], i32 16
240 // CHECK: store ptr [[NEXT]], ptr @the_list, align 4
241 // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 16 %agg.result, ptr align 8 [[CUR_ALIGNED]], i32 16, i1 false)
246 long long val
__attribute__((packed
,aligned(2)));
247 } underaligned_long_long_struct_member
;
248 underaligned_long_long_struct_member
underaligned_long_long_struct_member_test(void) {
249 // CHECK-LABEL: define{{.*}} void @underaligned_long_long_struct_member_test(ptr noalias sret(%struct.underaligned_long_long_struct_member) align 2 %agg.result)
250 return va_arg(the_list
, underaligned_long_long_struct_member
);
251 // CHECK: [[CUR:%[a-z0-9._]+]] = load ptr, ptr @the_list, align 4
252 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, ptr [[CUR]], i32 8
253 // CHECK: store ptr [[NEXT]], ptr @the_list, align 4
254 // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 2 %agg.result, ptr align 4 [[CUR]], i32 8, i1 false)
259 long long val
__attribute__((aligned(16)));
260 } overaligned_long_long_struct_member
;
261 overaligned_long_long_struct_member
overaligned_long_long_struct_member_test(void) {
262 // CHECK-LABEL: define{{.*}} void @overaligned_long_long_struct_member_test(ptr noalias sret(%struct.overaligned_long_long_struct_member) align 16 %agg.result)
263 return va_arg(the_list
, overaligned_long_long_struct_member
);
264 // CHECK: [[CUR:%[a-z0-9._]+]] = load ptr, ptr @the_list, align 4
265 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint ptr [[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 ptr
269 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, ptr [[CUR_ALIGNED]], i32 16
270 // CHECK: store ptr [[NEXT]], ptr @the_list, align 4
271 // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 16 %agg.result, ptr align 8 [[CUR_ALIGNED]], i32 16, i1 false)
275 void check_start(int n
, ...) {
276 // CHECK-LABEL: define{{.*}} void @check_start(i32 noundef %n, ...)
279 va_start(the_list
, n
);
280 // CHECK: [[THE_LIST:%[a-z0-9._]+]] = alloca %struct.__va_list
281 // CHECK: call void @llvm.va_start(ptr [[THE_LIST]])