[SLP]Propagate AssumptionCache where possible
[llvm-project.git] / clang / test / CodeGen / AArch64 / varargs.c
blob86fba012f7025a9de0e825bcbb66954bb8c43cdb
1 // RUN: %clang_cc1 -triple arm64-linux-gnu -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-LE %s
2 // RUN: %clang_cc1 -triple aarch64_be-linux-gnu -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-BE %s
4 #include <stdarg.h>
6 // Obviously there's more than one way to implement va_arg. This test should at
7 // least prevent unintentional regressions caused by refactoring.
9 va_list the_list;
11 int simple_int(void) {
12 // CHECK-LABEL: define{{.*}} i32 @simple_int
13 return va_arg(the_list, int);
14 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
15 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
16 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
18 // CHECK: [[VAARG_MAYBE_REG]]
19 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
20 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
21 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
22 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
24 // CHECK: [[VAARG_IN_REG]]
25 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
26 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
27 // CHECK-BE: [[REG_ADDR_ALIGNED:%[0-9]+]] = getelementptr inbounds i8, ptr [[REG_ADDR]], i64 4
28 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
30 // CHECK: [[VAARG_ON_STACK]]
31 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
32 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
33 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
34 // CHECK-BE: [[STACK_ALIGNED:%[a-z_0-9]*]] = getelementptr inbounds i8, ptr [[STACK]], i64 4
35 // CHECK: br label %[[VAARG_END]]
37 // CHECK: [[VAARG_END]]
38 // CHECK-LE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
39 // CHECK-BE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR_ALIGNED]], %[[VAARG_IN_REG]] ], [ [[STACK_ALIGNED]], %[[VAARG_ON_STACK]] ]
40 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i32, ptr [[ADDR]]
41 // CHECK: ret i32 [[RESULT]]
44 __int128 aligned_int(void) {
45 // CHECK-LABEL: define{{.*}} i128 @aligned_int
46 return va_arg(the_list, __int128);
47 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
48 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
49 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
51 // CHECK: [[VAARG_MAYBE_REG]]
52 // CHECK: [[ALIGN_REGOFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 15
53 // CHECK: [[ALIGNED_REGOFFS:%[a-z_0-9]+]] = and i32 [[ALIGN_REGOFFS]], -16
54 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[ALIGNED_REGOFFS]], 16
55 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
56 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
57 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
59 // CHECK: [[VAARG_IN_REG]]
60 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
61 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[ALIGNED_REGOFFS]]
62 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
64 // CHECK: [[VAARG_ON_STACK]]
65 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
66 // CHECK: [[STACKINC:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i32 15
67 // CHECK: [[ALIGNED_STACK_PTR:%[a-z_0-9.]+]] = call ptr @llvm.ptrmask.p0.i64(ptr [[STACKINC]], i64 -16)
68 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[ALIGNED_STACK_PTR]], i64 16
69 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
70 // CHECK: br label %[[VAARG_END]]
72 // CHECK: [[VAARG_END]]
73 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[ALIGNED_STACK_PTR]], %[[VAARG_ON_STACK]] ]
74 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i128, ptr [[ADDR]]
75 // CHECK: ret i128 [[RESULT]]
78 struct bigstruct {
79 int a[10];
82 struct bigstruct simple_indirect(void) {
83 // CHECK-LABEL: define{{.*}} void @simple_indirect
84 return va_arg(the_list, struct bigstruct);
85 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
86 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
87 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
89 // CHECK: [[VAARG_MAYBE_REG]]
90 // CHECK-NOT: and i32
91 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
92 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
93 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
94 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
96 // CHECK: [[VAARG_IN_REG]]
97 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
98 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
99 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
101 // CHECK: [[VAARG_ON_STACK]]
102 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
103 // CHECK-NOT: and i64
104 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
105 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
106 // CHECK: br label %[[VAARG_END]]
108 // CHECK: [[VAARG_END]]
109 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
110 // CHECK: load ptr, ptr [[ADDR]]
113 struct aligned_bigstruct {
114 float a;
115 long double b;
118 struct aligned_bigstruct simple_aligned_indirect(void) {
119 // CHECK-LABEL: define{{.*}} void @simple_aligned_indirect
120 return va_arg(the_list, struct aligned_bigstruct);
121 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
122 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
123 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
125 // CHECK: [[VAARG_MAYBE_REG]]
126 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
127 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
128 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
129 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
131 // CHECK: [[VAARG_IN_REG]]
132 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
133 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
134 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
136 // CHECK: [[VAARG_ON_STACK]]
137 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
138 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
139 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
140 // CHECK: br label %[[VAARG_END]]
142 // CHECK: [[VAARG_END]]
143 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
144 // CHECK: load ptr, ptr [[ADDR]]
147 double simple_double(void) {
148 // CHECK-LABEL: define{{.*}} double @simple_double
149 return va_arg(the_list, double);
150 // CHECK: [[VR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 4)
151 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[VR_OFFS]], 0
152 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG]]
154 // CHECK: [[VAARG_MAYBE_REG]]
155 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[VR_OFFS]], 16
156 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 4)
157 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
158 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
160 // CHECK: [[VAARG_IN_REG]]
161 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 2)
162 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[VR_OFFS]]
163 // CHECK-BE: [[REG_ADDR_ALIGNED:%[a-z_0-9]*]] = getelementptr inbounds i8, ptr [[REG_ADDR]], i64 8
164 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
166 // CHECK: [[VAARG_ON_STACK]]
167 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
168 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
169 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
170 // CHECK: br label %[[VAARG_END]]
172 // CHECK: [[VAARG_END]]
173 // CHECK-LE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
174 // CHECK-BE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR_ALIGNED]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
175 // CHECK: [[RESULT:%[a-z_0-9]+]] = load double, ptr [[ADDR]]
176 // CHECK: ret double [[RESULT]]
179 struct hfa {
180 float a, b;
183 struct hfa simple_hfa(void) {
184 // CHECK-LABEL: define{{.*}} %struct.hfa @simple_hfa
185 return va_arg(the_list, struct hfa);
186 // CHECK: [[VR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 4)
187 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[VR_OFFS]], 0
188 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
190 // CHECK: [[VAARG_MAYBE_REG]]
191 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[VR_OFFS]], 32
192 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 4)
193 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
194 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
196 // CHECK: [[VAARG_IN_REG]]
197 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 2)
198 // CHECK: [[FIRST_REG:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[VR_OFFS]]
199 // CHECK-LE: [[EL_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[FIRST_REG]], i64 0
200 // CHECK-BE: [[EL_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[FIRST_REG]], i64 12
201 // CHECK: [[EL_TMPADDR:%[a-z_0-9]+]] = getelementptr inbounds [2 x float], ptr %[[TMP_HFA:[a-z_.0-9]+]], i64 0, i64 0
202 // CHECK: [[EL:%[a-z_0-9]+]] = load float, ptr [[EL_ADDR]]
203 // CHECK: store float [[EL]], ptr [[EL_TMPADDR]]
204 // CHECK-LE: [[EL_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[FIRST_REG]], i64 16
205 // CHECK-BE: [[EL_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[FIRST_REG]], i64 28
206 // CHECK: [[EL_TMPADDR:%[a-z_0-9]+]] = getelementptr inbounds [2 x float], ptr %[[TMP_HFA]], i64 0, i64 1
207 // CHECK: [[EL:%[a-z_0-9]+]] = load float, ptr [[EL_ADDR]]
208 // CHECK: store float [[EL]], ptr [[EL_TMPADDR]]
209 // CHECK: br label %[[VAARG_END:[a-z_.0-9]+]]
211 // CHECK: [[VAARG_ON_STACK]]
212 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
213 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
214 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
215 // CHECK: br label %[[VAARG_END]]
217 // CHECK: [[VAARG_END]]
218 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ %[[TMP_HFA]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
221 // Over and under alignment on fundamental types has no effect on parameter
222 // passing, so the code generated for va_arg should be the same as for
223 // non-aligned fundamental types.
225 typedef int underaligned_int __attribute__((packed,aligned(2)));
226 underaligned_int underaligned_int_test(void) {
227 // CHECK-LABEL: define{{.*}} i32 @underaligned_int_test()
228 return va_arg(the_list, underaligned_int);
229 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
230 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
231 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
233 // CHECK: [[VAARG_MAYBE_REG]]
234 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
235 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
236 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
237 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
239 // CHECK: [[VAARG_IN_REG]]
240 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
241 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
242 // CHECK-BE: [[REG_ADDR_ALIGNED:%[0-9]+]] = getelementptr inbounds i8, ptr [[REG_ADDR]], i64 4
243 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
245 // CHECK: [[VAARG_ON_STACK]]
246 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
247 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
248 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
249 // CHECK-BE: [[STACK_ALIGNED:%[a-z_0-9]*]] = getelementptr inbounds i8, ptr [[STACK]], i64 4
250 // CHECK: br label %[[VAARG_END]]
252 // CHECK: [[VAARG_END]]
253 // CHECK-LE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
254 // CHECK-BE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR_ALIGNED]], %[[VAARG_IN_REG]] ], [ [[STACK_ALIGNED]], %[[VAARG_ON_STACK]] ]
255 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i32, ptr [[ADDR]]
256 // CHECK: ret i32 [[RESULT]]
259 typedef int overaligned_int __attribute__((aligned(32)));
260 overaligned_int overaligned_int_test(void) {
261 // CHECK-LABEL: define{{.*}} i32 @overaligned_int_test()
262 return va_arg(the_list, overaligned_int);
263 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
264 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
265 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
267 // CHECK: [[VAARG_MAYBE_REG]]
268 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
269 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
270 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
271 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
273 // CHECK: [[VAARG_IN_REG]]
274 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
275 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
276 // CHECK-BE: [[REG_ADDR_ALIGNED:%[0-9]+]] = getelementptr inbounds i8, ptr [[REG_ADDR]], i64 4
277 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
279 // CHECK: [[VAARG_ON_STACK]]
280 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
281 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
282 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
283 // CHECK-BE: [[STACK_ALIGNED:%[a-z_0-9]*]] = getelementptr inbounds i8, ptr [[STACK]], i64 4
284 // CHECK: br label %[[VAARG_END]]
286 // CHECK: [[VAARG_END]]
287 // CHECK-LE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
288 // CHECK-BE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR_ALIGNED]], %[[VAARG_IN_REG]] ], [ [[STACK_ALIGNED]], %[[VAARG_ON_STACK]] ]
289 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i32, ptr [[ADDR]]
290 // CHECK: ret i32 [[RESULT]]
293 typedef long long underaligned_long_long __attribute__((packed,aligned(2)));
294 underaligned_long_long underaligned_long_long_test(void) {
295 // CHECK-LABEL: define{{.*}} i64 @underaligned_long_long_test()
296 return va_arg(the_list, underaligned_long_long);
297 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
298 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
299 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
301 // CHECK: [[VAARG_MAYBE_REG]]
302 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
303 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
304 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
305 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
307 // CHECK: [[VAARG_IN_REG]]
308 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
309 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
310 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
312 // CHECK: [[VAARG_ON_STACK]]
313 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
314 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
315 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
316 // CHECK: br label %[[VAARG_END]]
318 // CHECK: [[VAARG_END]]
319 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
320 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i64, ptr [[ADDR]]
321 // CHECK: ret i64 [[RESULT]]
324 typedef long long overaligned_long_long __attribute__((aligned(32)));
325 overaligned_long_long overaligned_long_long_test(void) {
326 // CHECK-LABEL: define{{.*}} i64 @overaligned_long_long_test()
327 return va_arg(the_list, overaligned_long_long);
328 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
329 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
330 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
332 // CHECK: [[VAARG_MAYBE_REG]]
333 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
334 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
335 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
336 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
338 // CHECK: [[VAARG_IN_REG]]
339 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
340 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
341 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
343 // CHECK: [[VAARG_ON_STACK]]
344 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
345 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
346 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
347 // CHECK: br label %[[VAARG_END]]
349 // CHECK: [[VAARG_END]]
350 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
351 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i64, ptr [[ADDR]]
352 // CHECK: ret i64 [[RESULT]]
355 typedef __int128 underaligned_int128 __attribute__((packed,aligned(2)));
356 underaligned_int128 underaligned_int128_test(void) {
357 // CHECK-LABEL: define{{.*}} i128 @underaligned_int128_test()
358 return va_arg(the_list, underaligned_int128);
359 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
360 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
361 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
363 // CHECK: [[VAARG_MAYBE_REG]]
364 // CHECK: [[ALIGN_REGOFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 15
365 // CHECK: [[ALIGNED_REGOFFS:%[a-z_0-9]+]] = and i32 [[ALIGN_REGOFFS]], -16
366 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[ALIGNED_REGOFFS]], 16
367 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
368 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
369 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
371 // CHECK: [[VAARG_IN_REG]]
372 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
373 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[ALIGNED_REGOFFS]]
374 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
376 // CHECK: [[VAARG_ON_STACK]]
377 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
378 // CHECK: [[STACKINC:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i32 15
379 // CHECK: [[ALIGNED_STACK_PTR:%[a-z_0-9.]+]] = call ptr @llvm.ptrmask.p0.i64(ptr [[STACKINC]], i64 -16)
380 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[ALIGNED_STACK_PTR]], i64 16
381 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
382 // CHECK: br label %[[VAARG_END]]
384 // CHECK: [[VAARG_END]]
385 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[ALIGNED_STACK_PTR]], %[[VAARG_ON_STACK]] ]
386 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i128, ptr [[ADDR]]
387 // CHECK: ret i128 [[RESULT]]
390 typedef __int128 overaligned_int128 __attribute__((aligned(32)));
391 overaligned_int128 overaligned_int128_test(void) {
392 // CHECK-LABEL: define{{.*}} i128 @overaligned_int128_test()
393 return va_arg(the_list, overaligned_int128);
394 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
395 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
396 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
398 // CHECK: [[VAARG_MAYBE_REG]]
399 // CHECK: [[ALIGN_REGOFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 15
400 // CHECK: [[ALIGNED_REGOFFS:%[a-z_0-9]+]] = and i32 [[ALIGN_REGOFFS]], -16
401 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[ALIGNED_REGOFFS]], 16
402 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
403 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
404 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
406 // CHECK: [[VAARG_IN_REG]]
407 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
408 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[ALIGNED_REGOFFS]]
409 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
411 // CHECK: [[VAARG_ON_STACK]]
412 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
413 // CHECK: [[STACKINC:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i32 15
414 // CHECK: [[ALIGNED_STACK_PTR:%[a-z_0-9.]+]] = call ptr @llvm.ptrmask.p0.i64(ptr [[STACKINC]], i64 -16)
415 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[ALIGNED_STACK_PTR]], i64 16
416 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
417 // CHECK: br label %[[VAARG_END]]
419 // CHECK: [[VAARG_END]]
420 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[ALIGNED_STACK_PTR]], %[[VAARG_ON_STACK]] ]
421 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i128, ptr [[ADDR]]
422 // CHECK: ret i128 [[RESULT]]
425 // The way that attributes applied to a struct change parameter passing is a
426 // little strange, in that the alignment due to attributes is used when
427 // calculating the size of the struct, but the alignment is based only on the
428 // alignment of the members (which can be affected by attributes). What this
429 // means is:
430 // * The only effect of the aligned attribute on a struct is to increase its
431 // size if the alignment is greater than the member alignment.
432 // * The packed attribute is considered as applying to the members, so it will
433 // affect the alignment.
434 // Additionally the alignment can't go below 8 or above 16, so it's only
435 // __int128 that can be affected by a change in alignment.
437 typedef struct __attribute__((packed,aligned(2))) {
438 int val;
439 } underaligned_int_struct;
440 underaligned_int_struct underaligned_int_struct_test(void) {
441 // CHECK-LE-LABEL: define{{.*}} i32 @underaligned_int_struct_test()
442 // CHECK-BE-LABEL: define{{.*}} i64 @underaligned_int_struct_test()
443 return va_arg(the_list, underaligned_int_struct);
444 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
445 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
446 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
448 // CHECK: [[VAARG_MAYBE_REG]]
449 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
450 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
451 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
452 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
454 // CHECK: [[VAARG_IN_REG]]
455 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
456 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
457 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
459 // CHECK: [[VAARG_ON_STACK]]
460 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
461 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
462 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
463 // CHECK: br label %[[VAARG_END]]
465 // CHECK: [[VAARG_END]]
466 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
469 typedef struct __attribute__((aligned(16))) {
470 int val;
471 } overaligned_int_struct;
472 overaligned_int_struct overaligned_int_struct_test(void) {
473 // CHECK-LABEL: define{{.*}} i128 @overaligned_int_struct_test()
474 return va_arg(the_list, overaligned_int_struct);
475 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
476 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
477 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
479 // CHECK: [[VAARG_MAYBE_REG]]
480 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 16
481 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
482 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
483 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
485 // CHECK: [[VAARG_IN_REG]]
486 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
487 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
488 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
490 // CHECK: [[VAARG_ON_STACK]]
491 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
492 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 16
493 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
494 // CHECK: br label %[[VAARG_END]]
496 // CHECK: [[VAARG_END]]
497 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
500 typedef struct __attribute__((packed,aligned(2))) {
501 long long val;
502 } underaligned_long_long_struct;
503 underaligned_long_long_struct underaligned_long_long_struct_test(void) {
504 // CHECK-LABEL: define{{.*}} i64 @underaligned_long_long_struct_test()
505 return va_arg(the_list, underaligned_long_long_struct);
506 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
507 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
508 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
510 // CHECK: [[VAARG_MAYBE_REG]]
511 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
512 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
513 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
514 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
516 // CHECK: [[VAARG_IN_REG]]
517 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
518 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
519 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
521 // CHECK: [[VAARG_ON_STACK]]
522 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
523 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
524 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
525 // CHECK: br label %[[VAARG_END]]
527 // CHECK: [[VAARG_END]]
528 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
531 typedef struct __attribute__((aligned(16))) {
532 long long val;
533 } overaligned_long_long_struct;
534 overaligned_long_long_struct overaligned_long_long_struct_test(void) {
535 // CHECK-LABEL: define{{.*}} i128 @overaligned_long_long_struct_test()
536 return va_arg(the_list, overaligned_long_long_struct);
537 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
538 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
539 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
541 // CHECK: [[VAARG_MAYBE_REG]]
542 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 16
543 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
544 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
545 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
547 // CHECK: [[VAARG_IN_REG]]
548 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
549 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
550 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
552 // CHECK: [[VAARG_ON_STACK]]
553 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
554 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 16
555 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
556 // CHECK: br label %[[VAARG_END]]
558 // CHECK: [[VAARG_END]]
559 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
562 typedef struct __attribute__((packed,aligned(2))) {
563 __int128 val;
564 } underaligned_int128_struct;
565 underaligned_int128_struct underaligned_int128_struct_test(void) {
566 // CHECK-LABEL: define{{.*}} [2 x i64] @underaligned_int128_struct_test()
567 return va_arg(the_list, underaligned_int128_struct);
568 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
569 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
570 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
572 // CHECK: [[VAARG_MAYBE_REG]]
573 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 16
574 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
575 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
576 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
578 // CHECK: [[VAARG_IN_REG]]
579 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
580 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
581 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
583 // CHECK: [[VAARG_ON_STACK]]
584 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
585 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 16
586 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
587 // CHECK: br label %[[VAARG_END]]
589 // CHECK: [[VAARG_END]]
590 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
593 // Overaligning to 32 bytes causes it to be passed indirectly via a pointer
594 typedef struct __attribute__((aligned(32))) {
595 __int128 val;
596 } overaligned_int128_struct;
597 overaligned_int128_struct overaligned_int128_struct_test(void) {
598 // CHECK-LABEL: define{{.*}} void @overaligned_int128_struct_test(ptr dead_on_unwind noalias writable sret(%struct.overaligned_int128_struct) align 32 %agg.result)
599 return va_arg(the_list, overaligned_int128_struct);
600 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
601 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
602 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
604 // CHECK: [[VAARG_MAYBE_REG]]
605 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
606 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
607 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
608 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
610 // CHECK: [[VAARG_IN_REG]]
611 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
612 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
613 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
615 // CHECK: [[VAARG_ON_STACK]]
616 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
617 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
618 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
619 // CHECK: br label %[[VAARG_END]]
621 // CHECK: [[VAARG_END]]
622 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
625 // Overaligning or underaligning a struct member changes both its alignment and
626 // size when passed as an argument.
628 typedef struct {
629 int val __attribute__((packed,aligned(2)));
630 } underaligned_int_struct_member;
631 underaligned_int_struct_member underaligned_int_struct_member_test(void) {
632 // CHECK-LE-LABEL: define{{.*}} i32 @underaligned_int_struct_member_test()
633 // CHECK-BE-LABEL: define{{.*}} i64 @underaligned_int_struct_member_test()
634 return va_arg(the_list, underaligned_int_struct_member);
635 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
636 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
637 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
639 // CHECK: [[VAARG_MAYBE_REG]]
640 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
641 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
642 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
643 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
645 // CHECK: [[VAARG_IN_REG]]
646 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
647 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
648 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
650 // CHECK: [[VAARG_ON_STACK]]
651 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
652 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
653 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
654 // CHECK: br label %[[VAARG_END]]
656 // CHECK: [[VAARG_END]]
657 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
660 typedef struct {
661 int val __attribute__((aligned(16)));
662 } overaligned_int_struct_member;
663 overaligned_int_struct_member overaligned_int_struct_member_test(void) {
664 // CHECK-LABEL: define{{.*}} i128 @overaligned_int_struct_member_test()
665 return va_arg(the_list, overaligned_int_struct_member);
666 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
667 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
668 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
670 // CHECK: [[VAARG_MAYBE_REG]]
671 // CHECK: [[ALIGN_REGOFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 15
672 // CHECK: [[ALIGNED_REGOFFS:%[a-z_0-9]+]] = and i32 [[ALIGN_REGOFFS]], -16
673 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[ALIGNED_REGOFFS]], 16
674 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
675 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
676 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
678 // CHECK: [[VAARG_IN_REG]]
679 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
680 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[ALIGNED_REGOFFS]]
681 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
683 // CHECK: [[VAARG_ON_STACK]]
684 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
685 // CHECK: [[STACKINC:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i32 15
686 // CHECK: [[ALIGNED_STACK_PTR:%[a-z_0-9.]+]] = call ptr @llvm.ptrmask.p0.i64(ptr [[STACKINC]], i64 -16)
687 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[ALIGNED_STACK_PTR]], i64 16
688 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
689 // CHECK: br label %[[VAARG_END]]
691 // CHECK: [[VAARG_END]]
692 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[ALIGNED_STACK_PTR]], %[[VAARG_ON_STACK]] ]
695 typedef struct {
696 long long val __attribute__((packed,aligned(2)));
697 } underaligned_long_long_struct_member;
698 underaligned_long_long_struct_member underaligned_long_long_struct_member_test(void) {
699 // CHECK-LABEL: define{{.*}} i64 @underaligned_long_long_struct_member_test()
700 return va_arg(the_list, underaligned_long_long_struct_member);
701 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
702 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
703 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
705 // CHECK: [[VAARG_MAYBE_REG]]
706 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
707 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
708 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
709 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
711 // CHECK: [[VAARG_IN_REG]]
712 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
713 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
714 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
716 // CHECK: [[VAARG_ON_STACK]]
717 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
718 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
719 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
720 // CHECK: br label %[[VAARG_END]]
722 // CHECK: [[VAARG_END]]
723 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
726 typedef struct {
727 long long val __attribute__((aligned(16)));
728 } overaligned_long_long_struct_member;
729 overaligned_long_long_struct_member overaligned_long_long_struct_member_test(void) {
730 // CHECK-LABEL: define{{.*}} i128 @overaligned_long_long_struct_member_test()
731 return va_arg(the_list, overaligned_long_long_struct_member);
732 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
733 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
734 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
736 // CHECK: [[VAARG_MAYBE_REG]]
737 // CHECK: [[ALIGN_REGOFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 15
738 // CHECK: [[ALIGNED_REGOFFS:%[a-z_0-9]+]] = and i32 [[ALIGN_REGOFFS]], -16
739 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[ALIGNED_REGOFFS]], 16
740 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
741 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
742 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
744 // CHECK: [[VAARG_IN_REG]]
745 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
746 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[ALIGNED_REGOFFS]]
747 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
749 // CHECK: [[VAARG_ON_STACK]]
750 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
751 // CHECK: [[STACKINC:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i32 15
752 // CHECK: [[ALIGNED_STACK_PTR:%[a-z_0-9.]+]] = call ptr @llvm.ptrmask.p0.i64(ptr [[STACKINC]], i64 -16)
753 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[ALIGNED_STACK_PTR]], i64 16
754 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
755 // CHECK: br label %[[VAARG_END]]
757 // CHECK: [[VAARG_END]]
758 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[ALIGNED_STACK_PTR]], %[[VAARG_ON_STACK]] ]
761 typedef struct {
762 __int128 val __attribute__((packed,aligned(2)));
763 } underaligned_int128_struct_member;
764 underaligned_int128_struct_member underaligned_int128_struct_member_test(void) {
765 // CHECK-LABEL: define{{.*}} [2 x i64] @underaligned_int128_struct_member_test()
766 return va_arg(the_list, underaligned_int128_struct_member);
767 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
768 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
769 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
771 // CHECK: [[VAARG_MAYBE_REG]]
772 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 16
773 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
774 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
775 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
777 // CHECK: [[VAARG_IN_REG]]
778 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
779 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
780 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
782 // CHECK: [[VAARG_ON_STACK]]
783 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
784 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 16
785 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
786 // CHECK: br label %[[VAARG_END]]
788 // CHECK: [[VAARG_END]]
789 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
792 // Overaligning to 32 bytes causes it to be passed indirectly via a pointer
793 typedef struct {
794 __int128 val __attribute__((aligned(32)));
795 } overaligned_int128_struct_member;
796 overaligned_int128_struct_member overaligned_int128_struct_member_test(void) {
797 // CHECK-LABEL: define{{.*}} void @overaligned_int128_struct_member_test(ptr dead_on_unwind noalias writable sret(%struct.overaligned_int128_struct_member) align 32 %agg.result)
798 return va_arg(the_list, overaligned_int128_struct_member);
799 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
800 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
801 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
803 // CHECK: [[VAARG_MAYBE_REG]]
804 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
805 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3)
806 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
807 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
809 // CHECK: [[VAARG_IN_REG]]
810 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1)
811 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
812 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
814 // CHECK: [[VAARG_ON_STACK]]
815 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
816 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
817 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
818 // CHECK: br label %[[VAARG_END]]
820 // CHECK: [[VAARG_END]]
821 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
824 void check_start(int n, ...) {
825 // CHECK-LABEL: define{{.*}} void @check_start(i32 noundef %n, ...)
827 va_list the_list;
828 va_start(the_list, n);
829 // CHECK: [[THE_LIST:%[a-z_0-9]+]] = alloca %struct.__va_list
830 // CHECK: call void @llvm.va_start.p0(ptr [[THE_LIST]])
833 typedef struct {} empty;
834 empty empty_record_test(void) {
835 // CHECK-LABEL: define{{.*}} void @empty_record_test()
836 // CHECK: entry
837 // CHECK-NEXT: ret void
838 return va_arg(the_list, empty);