[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / clang / test / CodeGen / aarch64-varargs.c
blobf2ce7d59a8cce9bf03faca83007fb3a48d061098
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 (%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 (%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 (%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 (%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 (%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 (%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: [[STACKINT:%[a-z_0-9]+]] = ptrtoint ptr [[STACK]] to i64
67 // CHECK: [[ALIGN_STACK:%[a-z_0-9]+]] = add i64 [[STACKINT]], 15
68 // CHECK: [[ALIGNED_STACK_INT:%[a-z_0-9]+]] = and i64 [[ALIGN_STACK]], -16
69 // CHECK: [[ALIGNED_STACK_PTR:%[a-z_0-9]+]] = inttoptr i64 [[ALIGNED_STACK_INT]] to ptr
70 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[ALIGNED_STACK_PTR]], i64 16
71 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
72 // CHECK: br label %[[VAARG_END]]
74 // CHECK: [[VAARG_END]]
75 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[ALIGNED_STACK_PTR]], %[[VAARG_ON_STACK]] ]
76 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i128, ptr [[ADDR]]
77 // CHECK: ret i128 [[RESULT]]
80 struct bigstruct {
81 int a[10];
84 struct bigstruct simple_indirect(void) {
85 // CHECK-LABEL: define{{.*}} void @simple_indirect
86 return va_arg(the_list, struct bigstruct);
87 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
88 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
89 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
91 // CHECK: [[VAARG_MAYBE_REG]]
92 // CHECK-NOT: and i32
93 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
94 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
95 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
96 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
98 // CHECK: [[VAARG_IN_REG]]
99 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 1)
100 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
101 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
103 // CHECK: [[VAARG_ON_STACK]]
104 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
105 // CHECK-NOT: and i64
106 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
107 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
108 // CHECK: br label %[[VAARG_END]]
110 // CHECK: [[VAARG_END]]
111 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
112 // CHECK: load ptr, ptr [[ADDR]]
115 struct aligned_bigstruct {
116 float a;
117 long double b;
120 struct aligned_bigstruct simple_aligned_indirect(void) {
121 // CHECK-LABEL: define{{.*}} void @simple_aligned_indirect
122 return va_arg(the_list, struct aligned_bigstruct);
123 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
124 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
125 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
127 // CHECK: [[VAARG_MAYBE_REG]]
128 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
129 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
130 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
131 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
133 // CHECK: [[VAARG_IN_REG]]
134 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 1)
135 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
136 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
138 // CHECK: [[VAARG_ON_STACK]]
139 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
140 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
141 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
142 // CHECK: br label %[[VAARG_END]]
144 // CHECK: [[VAARG_END]]
145 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
146 // CHECK: load ptr, ptr [[ADDR]]
149 double simple_double(void) {
150 // CHECK-LABEL: define{{.*}} double @simple_double
151 return va_arg(the_list, double);
152 // CHECK: [[VR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 4)
153 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[VR_OFFS]], 0
154 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG]]
156 // CHECK: [[VAARG_MAYBE_REG]]
157 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[VR_OFFS]], 16
158 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 4)
159 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
160 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
162 // CHECK: [[VAARG_IN_REG]]
163 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 2)
164 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[VR_OFFS]]
165 // CHECK-BE: [[REG_ADDR_ALIGNED:%[a-z_0-9]*]] = getelementptr inbounds i8, ptr [[REG_ADDR]], i64 8
166 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
168 // CHECK: [[VAARG_ON_STACK]]
169 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
170 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
171 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
172 // CHECK: br label %[[VAARG_END]]
174 // CHECK: [[VAARG_END]]
175 // CHECK-LE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
176 // CHECK-BE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR_ALIGNED]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
177 // CHECK: [[RESULT:%[a-z_0-9]+]] = load double, ptr [[ADDR]]
178 // CHECK: ret double [[RESULT]]
181 struct hfa {
182 float a, b;
185 struct hfa simple_hfa(void) {
186 // CHECK-LABEL: define{{.*}} %struct.hfa @simple_hfa
187 return va_arg(the_list, struct hfa);
188 // CHECK: [[VR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 4)
189 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[VR_OFFS]], 0
190 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
192 // CHECK: [[VAARG_MAYBE_REG]]
193 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[VR_OFFS]], 32
194 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 4)
195 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
196 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
198 // CHECK: [[VAARG_IN_REG]]
199 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 2)
200 // CHECK: [[FIRST_REG:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[VR_OFFS]]
201 // CHECK-LE: [[EL_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[FIRST_REG]], i64 0
202 // CHECK-BE: [[EL_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[FIRST_REG]], i64 12
203 // CHECK: [[EL_TMPADDR:%[a-z_0-9]+]] = getelementptr inbounds [2 x float], ptr %[[TMP_HFA:[a-z_.0-9]+]], i64 0, i64 0
204 // CHECK: [[EL:%[a-z_0-9]+]] = load float, ptr [[EL_ADDR]]
205 // CHECK: store float [[EL]], ptr [[EL_TMPADDR]]
206 // CHECK-LE: [[EL_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[FIRST_REG]], i64 16
207 // CHECK-BE: [[EL_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[FIRST_REG]], i64 28
208 // CHECK: [[EL_TMPADDR:%[a-z_0-9]+]] = getelementptr inbounds [2 x float], ptr %[[TMP_HFA]], i64 0, i64 1
209 // CHECK: [[EL:%[a-z_0-9]+]] = load float, ptr [[EL_ADDR]]
210 // CHECK: store float [[EL]], ptr [[EL_TMPADDR]]
211 // CHECK: br label %[[VAARG_END:[a-z_.0-9]+]]
213 // CHECK: [[VAARG_ON_STACK]]
214 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
215 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
216 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
217 // CHECK: br label %[[VAARG_END]]
219 // CHECK: [[VAARG_END]]
220 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ %[[TMP_HFA]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
223 // Over and under alignment on fundamental types has no effect on parameter
224 // passing, so the code generated for va_arg should be the same as for
225 // non-aligned fundamental types.
227 typedef int underaligned_int __attribute__((packed,aligned(2)));
228 underaligned_int underaligned_int_test(void) {
229 // CHECK-LABEL: define{{.*}} i32 @underaligned_int_test()
230 return va_arg(the_list, underaligned_int);
231 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
232 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
233 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
235 // CHECK: [[VAARG_MAYBE_REG]]
236 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
237 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
238 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
239 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
241 // CHECK: [[VAARG_IN_REG]]
242 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 1)
243 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
244 // CHECK-BE: [[REG_ADDR_ALIGNED:%[0-9]+]] = getelementptr inbounds i8, ptr [[REG_ADDR]], i64 4
245 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
247 // CHECK: [[VAARG_ON_STACK]]
248 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
249 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
250 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
251 // CHECK-BE: [[STACK_ALIGNED:%[a-z_0-9]*]] = getelementptr inbounds i8, ptr [[STACK]], i64 4
252 // CHECK: br label %[[VAARG_END]]
254 // CHECK: [[VAARG_END]]
255 // CHECK-LE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
256 // CHECK-BE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR_ALIGNED]], %[[VAARG_IN_REG]] ], [ [[STACK_ALIGNED]], %[[VAARG_ON_STACK]] ]
257 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i32, ptr [[ADDR]]
258 // CHECK: ret i32 [[RESULT]]
261 typedef int overaligned_int __attribute__((aligned(32)));
262 overaligned_int overaligned_int_test(void) {
263 // CHECK-LABEL: define{{.*}} i32 @overaligned_int_test()
264 return va_arg(the_list, overaligned_int);
265 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
266 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
267 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
269 // CHECK: [[VAARG_MAYBE_REG]]
270 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
271 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
272 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
273 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
275 // CHECK: [[VAARG_IN_REG]]
276 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 1)
277 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
278 // CHECK-BE: [[REG_ADDR_ALIGNED:%[0-9]+]] = getelementptr inbounds i8, ptr [[REG_ADDR]], i64 4
279 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
281 // CHECK: [[VAARG_ON_STACK]]
282 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
283 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
284 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
285 // CHECK-BE: [[STACK_ALIGNED:%[a-z_0-9]*]] = getelementptr inbounds i8, ptr [[STACK]], i64 4
286 // CHECK: br label %[[VAARG_END]]
288 // CHECK: [[VAARG_END]]
289 // CHECK-LE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
290 // CHECK-BE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR_ALIGNED]], %[[VAARG_IN_REG]] ], [ [[STACK_ALIGNED]], %[[VAARG_ON_STACK]] ]
291 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i32, ptr [[ADDR]]
292 // CHECK: ret i32 [[RESULT]]
295 typedef long long underaligned_long_long __attribute__((packed,aligned(2)));
296 underaligned_long_long underaligned_long_long_test(void) {
297 // CHECK-LABEL: define{{.*}} i64 @underaligned_long_long_test()
298 return va_arg(the_list, underaligned_long_long);
299 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
300 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
301 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
303 // CHECK: [[VAARG_MAYBE_REG]]
304 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
305 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
306 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
307 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
309 // CHECK: [[VAARG_IN_REG]]
310 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 1)
311 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
312 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
314 // CHECK: [[VAARG_ON_STACK]]
315 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
316 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
317 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
318 // CHECK: br label %[[VAARG_END]]
320 // CHECK: [[VAARG_END]]
321 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
322 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i64, ptr [[ADDR]]
323 // CHECK: ret i64 [[RESULT]]
326 typedef long long overaligned_long_long __attribute__((aligned(32)));
327 overaligned_long_long overaligned_long_long_test(void) {
328 // CHECK-LABEL: define{{.*}} i64 @overaligned_long_long_test()
329 return va_arg(the_list, overaligned_long_long);
330 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
331 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
332 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
334 // CHECK: [[VAARG_MAYBE_REG]]
335 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
336 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
337 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
338 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
340 // CHECK: [[VAARG_IN_REG]]
341 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 1)
342 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
343 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
345 // CHECK: [[VAARG_ON_STACK]]
346 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
347 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
348 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
349 // CHECK: br label %[[VAARG_END]]
351 // CHECK: [[VAARG_END]]
352 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
353 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i64, ptr [[ADDR]]
354 // CHECK: ret i64 [[RESULT]]
357 typedef __int128 underaligned_int128 __attribute__((packed,aligned(2)));
358 underaligned_int128 underaligned_int128_test(void) {
359 // CHECK-LABEL: define{{.*}} i128 @underaligned_int128_test()
360 return va_arg(the_list, underaligned_int128);
361 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
362 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
363 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
365 // CHECK: [[VAARG_MAYBE_REG]]
366 // CHECK: [[ALIGN_REGOFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 15
367 // CHECK: [[ALIGNED_REGOFFS:%[a-z_0-9]+]] = and i32 [[ALIGN_REGOFFS]], -16
368 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[ALIGNED_REGOFFS]], 16
369 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
370 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
371 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
373 // CHECK: [[VAARG_IN_REG]]
374 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 1)
375 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[ALIGNED_REGOFFS]]
376 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
378 // CHECK: [[VAARG_ON_STACK]]
379 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
380 // CHECK: [[STACKINT:%[a-z_0-9]+]] = ptrtoint ptr [[STACK]] to i64
381 // CHECK: [[ALIGN_STACK:%[a-z_0-9]+]] = add i64 [[STACKINT]], 15
382 // CHECK: [[ALIGNED_STACK_INT:%[a-z_0-9]+]] = and i64 [[ALIGN_STACK]], -16
383 // CHECK: [[ALIGNED_STACK_PTR:%[a-z_0-9]+]] = inttoptr i64 [[ALIGNED_STACK_INT]] to ptr
384 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[ALIGNED_STACK_PTR]], i64 16
385 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
386 // CHECK: br label %[[VAARG_END]]
388 // CHECK: [[VAARG_END]]
389 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[ALIGNED_STACK_PTR]], %[[VAARG_ON_STACK]] ]
390 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i128, ptr [[ADDR]]
391 // CHECK: ret i128 [[RESULT]]
394 typedef __int128 overaligned_int128 __attribute__((aligned(32)));
395 overaligned_int128 overaligned_int128_test(void) {
396 // CHECK-LABEL: define{{.*}} i128 @overaligned_int128_test()
397 return va_arg(the_list, overaligned_int128);
398 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
399 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
400 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
402 // CHECK: [[VAARG_MAYBE_REG]]
403 // CHECK: [[ALIGN_REGOFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 15
404 // CHECK: [[ALIGNED_REGOFFS:%[a-z_0-9]+]] = and i32 [[ALIGN_REGOFFS]], -16
405 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[ALIGNED_REGOFFS]], 16
406 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
407 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
408 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
410 // CHECK: [[VAARG_IN_REG]]
411 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 1)
412 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[ALIGNED_REGOFFS]]
413 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
415 // CHECK: [[VAARG_ON_STACK]]
416 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
417 // CHECK: [[STACKINT:%[a-z_0-9]+]] = ptrtoint ptr [[STACK]] to i64
418 // CHECK: [[ALIGN_STACK:%[a-z_0-9]+]] = add i64 [[STACKINT]], 15
419 // CHECK: [[ALIGNED_STACK_INT:%[a-z_0-9]+]] = and i64 [[ALIGN_STACK]], -16
420 // CHECK: [[ALIGNED_STACK_PTR:%[a-z_0-9]+]] = inttoptr i64 [[ALIGNED_STACK_INT]] to ptr
421 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[ALIGNED_STACK_PTR]], i64 16
422 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
423 // CHECK: br label %[[VAARG_END]]
425 // CHECK: [[VAARG_END]]
426 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[ALIGNED_STACK_PTR]], %[[VAARG_ON_STACK]] ]
427 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i128, ptr [[ADDR]]
428 // CHECK: ret i128 [[RESULT]]
431 // The way that attributes applied to a struct change parameter passing is a
432 // little strange, in that the alignment due to attributes is used when
433 // calculating the size of the struct, but the alignment is based only on the
434 // alignment of the members (which can be affected by attributes). What this
435 // means is:
436 // * The only effect of the aligned attribute on a struct is to increase its
437 // size if the alignment is greater than the member alignment.
438 // * The packed attribute is considered as applying to the members, so it will
439 // affect the alignment.
440 // Additionally the alignment can't go below 8 or above 16, so it's only
441 // __int128 that can be affected by a change in alignment.
443 typedef struct __attribute__((packed,aligned(2))) {
444 int val;
445 } underaligned_int_struct;
446 underaligned_int_struct underaligned_int_struct_test(void) {
447 // CHECK-LE-LABEL: define{{.*}} i32 @underaligned_int_struct_test()
448 // CHECK-BE-LABEL: define{{.*}} i64 @underaligned_int_struct_test()
449 return va_arg(the_list, underaligned_int_struct);
450 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
451 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
452 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
454 // CHECK: [[VAARG_MAYBE_REG]]
455 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
456 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
457 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
458 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
460 // CHECK: [[VAARG_IN_REG]]
461 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 1)
462 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
463 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
465 // CHECK: [[VAARG_ON_STACK]]
466 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
467 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
468 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
469 // CHECK: br label %[[VAARG_END]]
471 // CHECK: [[VAARG_END]]
472 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
475 typedef struct __attribute__((aligned(16))) {
476 int val;
477 } overaligned_int_struct;
478 overaligned_int_struct overaligned_int_struct_test(void) {
479 // CHECK-LABEL: define{{.*}} i128 @overaligned_int_struct_test()
480 return va_arg(the_list, overaligned_int_struct);
481 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
482 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
483 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
485 // CHECK: [[VAARG_MAYBE_REG]]
486 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 16
487 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
488 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
489 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
491 // CHECK: [[VAARG_IN_REG]]
492 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 1)
493 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
494 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
496 // CHECK: [[VAARG_ON_STACK]]
497 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
498 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 16
499 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
500 // CHECK: br label %[[VAARG_END]]
502 // CHECK: [[VAARG_END]]
503 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
506 typedef struct __attribute__((packed,aligned(2))) {
507 long long val;
508 } underaligned_long_long_struct;
509 underaligned_long_long_struct underaligned_long_long_struct_test(void) {
510 // CHECK-LABEL: define{{.*}} i64 @underaligned_long_long_struct_test()
511 return va_arg(the_list, underaligned_long_long_struct);
512 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
513 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
514 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
516 // CHECK: [[VAARG_MAYBE_REG]]
517 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
518 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
519 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
520 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
522 // CHECK: [[VAARG_IN_REG]]
523 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 1)
524 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
525 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
527 // CHECK: [[VAARG_ON_STACK]]
528 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
529 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
530 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
531 // CHECK: br label %[[VAARG_END]]
533 // CHECK: [[VAARG_END]]
534 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
537 typedef struct __attribute__((aligned(16))) {
538 long long val;
539 } overaligned_long_long_struct;
540 overaligned_long_long_struct overaligned_long_long_struct_test(void) {
541 // CHECK-LABEL: define{{.*}} i128 @overaligned_long_long_struct_test()
542 return va_arg(the_list, overaligned_long_long_struct);
543 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
544 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
545 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
547 // CHECK: [[VAARG_MAYBE_REG]]
548 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 16
549 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
550 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
551 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
553 // CHECK: [[VAARG_IN_REG]]
554 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 1)
555 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
556 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
558 // CHECK: [[VAARG_ON_STACK]]
559 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
560 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 16
561 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
562 // CHECK: br label %[[VAARG_END]]
564 // CHECK: [[VAARG_END]]
565 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
568 typedef struct __attribute__((packed,aligned(2))) {
569 __int128 val;
570 } underaligned_int128_struct;
571 underaligned_int128_struct underaligned_int128_struct_test(void) {
572 // CHECK-LABEL: define{{.*}} [2 x i64] @underaligned_int128_struct_test()
573 return va_arg(the_list, underaligned_int128_struct);
574 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
575 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
576 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
578 // CHECK: [[VAARG_MAYBE_REG]]
579 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 16
580 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
581 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
582 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
584 // CHECK: [[VAARG_IN_REG]]
585 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 1)
586 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
587 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
589 // CHECK: [[VAARG_ON_STACK]]
590 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
591 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 16
592 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
593 // CHECK: br label %[[VAARG_END]]
595 // CHECK: [[VAARG_END]]
596 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
599 // Overaligning to 32 bytes causes it to be passed indirectly via a pointer
600 typedef struct __attribute__((aligned(32))) {
601 __int128 val;
602 } overaligned_int128_struct;
603 overaligned_int128_struct overaligned_int128_struct_test(void) {
604 // CHECK-LABEL: define{{.*}} void @overaligned_int128_struct_test(ptr noalias sret(%struct.overaligned_int128_struct) align 32 %agg.result)
605 return va_arg(the_list, overaligned_int128_struct);
606 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
607 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
608 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
610 // CHECK: [[VAARG_MAYBE_REG]]
611 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
612 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
613 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
614 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
616 // CHECK: [[VAARG_IN_REG]]
617 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 1)
618 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
619 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
621 // CHECK: [[VAARG_ON_STACK]]
622 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
623 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
624 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
625 // CHECK: br label %[[VAARG_END]]
627 // CHECK: [[VAARG_END]]
628 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
631 // Overaligning or underaligning a struct member changes both its alignment and
632 // size when passed as an argument.
634 typedef struct {
635 int val __attribute__((packed,aligned(2)));
636 } underaligned_int_struct_member;
637 underaligned_int_struct_member underaligned_int_struct_member_test(void) {
638 // CHECK-LE-LABEL: define{{.*}} i32 @underaligned_int_struct_member_test()
639 // CHECK-BE-LABEL: define{{.*}} i64 @underaligned_int_struct_member_test()
640 return va_arg(the_list, underaligned_int_struct_member);
641 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
642 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
643 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
645 // CHECK: [[VAARG_MAYBE_REG]]
646 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
647 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
648 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
649 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
651 // CHECK: [[VAARG_IN_REG]]
652 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 1)
653 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
654 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
656 // CHECK: [[VAARG_ON_STACK]]
657 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
658 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
659 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
660 // CHECK: br label %[[VAARG_END]]
662 // CHECK: [[VAARG_END]]
663 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
666 typedef struct {
667 int val __attribute__((aligned(16)));
668 } overaligned_int_struct_member;
669 overaligned_int_struct_member overaligned_int_struct_member_test(void) {
670 // CHECK-LABEL: define{{.*}} i128 @overaligned_int_struct_member_test()
671 return va_arg(the_list, overaligned_int_struct_member);
672 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
673 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
674 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
676 // CHECK: [[VAARG_MAYBE_REG]]
677 // CHECK: [[ALIGN_REGOFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 15
678 // CHECK: [[ALIGNED_REGOFFS:%[a-z_0-9]+]] = and i32 [[ALIGN_REGOFFS]], -16
679 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[ALIGNED_REGOFFS]], 16
680 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
681 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
682 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
684 // CHECK: [[VAARG_IN_REG]]
685 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 1)
686 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[ALIGNED_REGOFFS]]
687 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
689 // CHECK: [[VAARG_ON_STACK]]
690 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
691 // CHECK: [[STACKINT:%[a-z_0-9]+]] = ptrtoint ptr [[STACK]] to i64
692 // CHECK: [[ALIGN_STACK:%[a-z_0-9]+]] = add i64 [[STACKINT]], 15
693 // CHECK: [[ALIGNED_STACK_INT:%[a-z_0-9]+]] = and i64 [[ALIGN_STACK]], -16
694 // CHECK: [[ALIGNED_STACK_PTR:%[a-z_0-9]+]] = inttoptr i64 [[ALIGNED_STACK_INT]] to ptr
695 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[ALIGNED_STACK_PTR]], i64 16
696 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
697 // CHECK: br label %[[VAARG_END]]
699 // CHECK: [[VAARG_END]]
700 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[ALIGNED_STACK_PTR]], %[[VAARG_ON_STACK]] ]
703 typedef struct {
704 long long val __attribute__((packed,aligned(2)));
705 } underaligned_long_long_struct_member;
706 underaligned_long_long_struct_member underaligned_long_long_struct_member_test(void) {
707 // CHECK-LABEL: define{{.*}} i64 @underaligned_long_long_struct_member_test()
708 return va_arg(the_list, underaligned_long_long_struct_member);
709 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
710 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
711 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
713 // CHECK: [[VAARG_MAYBE_REG]]
714 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
715 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
716 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
717 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
719 // CHECK: [[VAARG_IN_REG]]
720 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 1)
721 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
722 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
724 // CHECK: [[VAARG_ON_STACK]]
725 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
726 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
727 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
728 // CHECK: br label %[[VAARG_END]]
730 // CHECK: [[VAARG_END]]
731 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
734 typedef struct {
735 long long val __attribute__((aligned(16)));
736 } overaligned_long_long_struct_member;
737 overaligned_long_long_struct_member overaligned_long_long_struct_member_test(void) {
738 // CHECK-LABEL: define{{.*}} i128 @overaligned_long_long_struct_member_test()
739 return va_arg(the_list, overaligned_long_long_struct_member);
740 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
741 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
742 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
744 // CHECK: [[VAARG_MAYBE_REG]]
745 // CHECK: [[ALIGN_REGOFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 15
746 // CHECK: [[ALIGNED_REGOFFS:%[a-z_0-9]+]] = and i32 [[ALIGN_REGOFFS]], -16
747 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[ALIGNED_REGOFFS]], 16
748 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
749 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
750 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
752 // CHECK: [[VAARG_IN_REG]]
753 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 1)
754 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[ALIGNED_REGOFFS]]
755 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
757 // CHECK: [[VAARG_ON_STACK]]
758 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
759 // CHECK: [[STACKINT:%[a-z_0-9]+]] = ptrtoint ptr [[STACK]] to i64
760 // CHECK: [[ALIGN_STACK:%[a-z_0-9]+]] = add i64 [[STACKINT]], 15
761 // CHECK: [[ALIGNED_STACK_INT:%[a-z_0-9]+]] = and i64 [[ALIGN_STACK]], -16
762 // CHECK: [[ALIGNED_STACK_PTR:%[a-z_0-9]+]] = inttoptr i64 [[ALIGNED_STACK_INT]] to ptr
763 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[ALIGNED_STACK_PTR]], i64 16
764 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
765 // CHECK: br label %[[VAARG_END]]
767 // CHECK: [[VAARG_END]]
768 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[ALIGNED_STACK_PTR]], %[[VAARG_ON_STACK]] ]
771 typedef struct {
772 __int128 val __attribute__((packed,aligned(2)));
773 } underaligned_int128_struct_member;
774 underaligned_int128_struct_member underaligned_int128_struct_member_test(void) {
775 // CHECK-LABEL: define{{.*}} [2 x i64] @underaligned_int128_struct_member_test()
776 return va_arg(the_list, underaligned_int128_struct_member);
777 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
778 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
779 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
781 // CHECK: [[VAARG_MAYBE_REG]]
782 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 16
783 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
784 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
785 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
787 // CHECK: [[VAARG_IN_REG]]
788 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 1)
789 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
790 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
792 // CHECK: [[VAARG_ON_STACK]]
793 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
794 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 16
795 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
796 // CHECK: br label %[[VAARG_END]]
798 // CHECK: [[VAARG_END]]
799 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
802 // Overaligning to 32 bytes causes it to be passed indirectly via a pointer
803 typedef struct {
804 __int128 val __attribute__((aligned(32)));
805 } overaligned_int128_struct_member;
806 overaligned_int128_struct_member overaligned_int128_struct_member_test(void) {
807 // CHECK-LABEL: define{{.*}} void @overaligned_int128_struct_member_test(ptr noalias sret(%struct.overaligned_int128_struct_member) align 32 %agg.result)
808 return va_arg(the_list, overaligned_int128_struct_member);
809 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
810 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
811 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
813 // CHECK: [[VAARG_MAYBE_REG]]
814 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
815 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 3)
816 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
817 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
819 // CHECK: [[VAARG_IN_REG]]
820 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds (%struct.__va_list, ptr @the_list, i32 0, i32 1)
821 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]]
822 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
824 // CHECK: [[VAARG_ON_STACK]]
825 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list
826 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8
827 // CHECK: store ptr [[NEW_STACK]], ptr @the_list
828 // CHECK: br label %[[VAARG_END]]
830 // CHECK: [[VAARG_END]]
831 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ]
834 void check_start(int n, ...) {
835 // CHECK-LABEL: define{{.*}} void @check_start(i32 noundef %n, ...)
837 va_list the_list;
838 va_start(the_list, n);
839 // CHECK: [[THE_LIST:%[a-z_0-9]+]] = alloca %struct.__va_list
840 // CHECK: call void @llvm.va_start(ptr [[THE_LIST]])
843 typedef struct {} empty;
844 empty empty_record_test(void) {
845 // CHECK-LABEL: define{{.*}} void @empty_record_test()
846 return va_arg(the_list, empty);
847 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load ptr, ptr @the_list