xref: /llvm-project/clang/test/CodeGen/AArch64/varargs.c (revision 207e5ccceec8d3cc3f32723e78f2a142bc61b07d)
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
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 
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]+]]
17 
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]]
23 
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]+]]
29 
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]]
36 
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]]
42 }
43 
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]+]]
50 
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]]
58 
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]+]]
63 
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]]
71 
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]]
76 }
77 
78 struct bigstruct {
79   int a[10];
80 };
81 
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]+]]
88 
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]]
95 
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]+]]
100 
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]]
107 
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]]
111 }
112 
113 struct aligned_bigstruct {
114   float a;
115   long double b;
116 };
117 
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]+]]
124 
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]]
130 
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]+]]
135 
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]]
141 
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]]
145 }
146 
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]]
153 
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]]
159 
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]+]]
165 
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]]
171 
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]]
177 }
178 
179 struct hfa {
180   float a, b;
181 };
182 
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]+]]
189 
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]]
195 
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]+]]
210 
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]]
216 
217 // CHECK: [[VAARG_END]]
218 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ %[[TMP_HFA]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
219 }
220 
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.
224 
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]+]]
232 
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]]
238 
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]+]]
244 
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]]
251 
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]]
257 }
258 
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]+]]
266 
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]]
272 
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]+]]
278 
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]]
285 
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]]
291 }
292 
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]+]]
300 
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]]
306 
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]+]]
311 
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]]
317 
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]]
322 }
323 
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]+]]
331 
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]]
337 
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]+]]
342 
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]]
348 
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]]
353 }
354 
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]+]]
362 
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]]
370 
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]+]]
375 
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]]
383 
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]]
388 }
389 
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]+]]
397 
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]]
405 
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]+]]
410 
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]]
418 
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]]
423 }
424 
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.
436 
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]+]]
447 
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]]
453 
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]+]]
458 
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]]
464 
465 // CHECK: [[VAARG_END]]
466 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
467 }
468 
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]+]]
478 
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]]
484 
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]+]]
489 
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]]
495 
496 // CHECK: [[VAARG_END]]
497 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
498 }
499 
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]+]]
509 
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]]
515 
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]+]]
520 
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]]
526 
527 // CHECK: [[VAARG_END]]
528 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
529 }
530 
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]+]]
540 
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]]
546 
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]+]]
551 
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]]
557 
558 // CHECK: [[VAARG_END]]
559 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
560 }
561 
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]+]]
571 
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]]
577 
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]+]]
582 
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]]
588 
589 // CHECK: [[VAARG_END]]
590 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
591 }
592 
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]+]]
603 
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]]
609 
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]+]]
614 
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]]
620 
621 // CHECK: [[VAARG_END]]
622 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
623 }
624 
625 // Overaligning or underaligning a struct member changes both its alignment and
626 // size when passed as an argument.
627 
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]+]]
638 
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]]
644 
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]+]]
649 
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]]
655 
656 // CHECK: [[VAARG_END]]
657 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
658 }
659 
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]+]]
669 
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]]
677 
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]+]]
682 
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]]
690 
691 // CHECK: [[VAARG_END]]
692 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[ALIGNED_STACK_PTR]], %[[VAARG_ON_STACK]] ]
693 }
694 
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]+]]
704 
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]]
710 
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]+]]
715 
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]]
721 
722 // CHECK: [[VAARG_END]]
723 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
724 }
725 
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]+]]
735 
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]]
743 
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]+]]
748 
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]]
756 
757 // CHECK: [[VAARG_END]]
758 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[ALIGNED_STACK_PTR]], %[[VAARG_ON_STACK]] ]
759 }
760 
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]+]]
770 
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]]
776 
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]+]]
781 
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]]
787 
788 // CHECK: [[VAARG_END]]
789 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
790 }
791 
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]+]]
802 
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]]
808 
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]+]]
813 
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]]
819 
820 // CHECK: [[VAARG_END]]
821 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
822 }
823 
824 void check_start(int n, ...) {
825 // CHECK-LABEL: define{{.*}} void @check_start(i32 noundef %n, ...)
826 
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]])
831 }
832 
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);
839 }
840