1*0a6a1f1dSLionel Sambuc // RUN: %clang_cc1 -triple arm64-linux-gnu -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-LE %s
2*0a6a1f1dSLionel Sambuc // RUN: %clang_cc1 -triple aarch64_be-linux-gnu -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-BE %s
3*0a6a1f1dSLionel Sambuc
4f4a2713aSLionel Sambuc #include <stdarg.h>
5f4a2713aSLionel Sambuc
6f4a2713aSLionel Sambuc // Obviously there's more than one way to implement va_arg. This test should at
7f4a2713aSLionel Sambuc // least prevent unintentional regressions caused by refactoring.
8f4a2713aSLionel Sambuc
9f4a2713aSLionel Sambuc va_list the_list;
10f4a2713aSLionel Sambuc
simple_int(void)11f4a2713aSLionel Sambuc int simple_int(void) {
12f4a2713aSLionel Sambuc // CHECK-LABEL: define i32 @simple_int
13f4a2713aSLionel Sambuc return va_arg(the_list, int);
14f4a2713aSLionel Sambuc // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 3)
15f4a2713aSLionel Sambuc // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
16f4a2713aSLionel Sambuc // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
17f4a2713aSLionel Sambuc
18f4a2713aSLionel Sambuc // CHECK: [[VAARG_MAYBE_REG]]
19f4a2713aSLionel Sambuc // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
20f4a2713aSLionel Sambuc // CHECK: store i32 [[NEW_REG_OFFS]], i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 3)
21f4a2713aSLionel Sambuc // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
22f4a2713aSLionel Sambuc // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
23f4a2713aSLionel Sambuc
24f4a2713aSLionel Sambuc // CHECK: [[VAARG_IN_REG]]
25f4a2713aSLionel Sambuc // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 1)
26f4a2713aSLionel Sambuc // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr i8* [[REG_TOP]], i32 [[GR_OFFS]]
27*0a6a1f1dSLionel Sambuc // CHECK-BE: [[REG_ADDR_VAL:%[0-9]+]] = ptrtoint i8* [[REG_ADDR]] to i64
28*0a6a1f1dSLionel Sambuc // CHECK-BE: [[REG_ADDR_VAL_ALIGNED:%[a-z_0-9]*]] = add i64 [[REG_ADDR_VAL]], 4
29*0a6a1f1dSLionel Sambuc // CHECK-BE: [[REG_ADDR:%[0-9]+]] = inttoptr i64 [[REG_ADDR_VAL_ALIGNED]] to i8*
30f4a2713aSLionel Sambuc // CHECK: [[FROMREG_ADDR:%[a-z_0-9]+]] = bitcast i8* [[REG_ADDR]] to i32*
31f4a2713aSLionel Sambuc // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
32f4a2713aSLionel Sambuc
33f4a2713aSLionel Sambuc // CHECK: [[VAARG_ON_STACK]]
34f4a2713aSLionel Sambuc // CHECK: [[STACK:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
35f4a2713aSLionel Sambuc // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr i8* [[STACK]], i32 8
36f4a2713aSLionel Sambuc // CHECK: store i8* [[NEW_STACK]], i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
37*0a6a1f1dSLionel Sambuc // CHECK-BE: [[STACK_VAL:%[0-9]+]] = ptrtoint i8* [[STACK]] to i64
38*0a6a1f1dSLionel Sambuc // CHECK-BE: [[STACK_VAL_ALIGNED:%[a-z_0-9]*]] = add i64 [[STACK_VAL]], 4
39*0a6a1f1dSLionel Sambuc // CHECK-BE: [[STACK:%[0-9]+]] = inttoptr i64 [[STACK_VAL_ALIGNED]] to i8*
40f4a2713aSLionel Sambuc // CHECK: [[FROMSTACK_ADDR:%[a-z_0-9]+]] = bitcast i8* [[STACK]] to i32*
41f4a2713aSLionel Sambuc // CHECK: br label %[[VAARG_END]]
42f4a2713aSLionel Sambuc
43f4a2713aSLionel Sambuc // CHECK: [[VAARG_END]]
44f4a2713aSLionel Sambuc // CHECK: [[ADDR:%[a-z._0-9]+]] = phi i32* [ [[FROMREG_ADDR]], %[[VAARG_IN_REG]] ], [ [[FROMSTACK_ADDR]], %[[VAARG_ON_STACK]] ]
45f4a2713aSLionel Sambuc // CHECK: [[RESULT:%[a-z_0-9]+]] = load i32* [[ADDR]]
46f4a2713aSLionel Sambuc // CHECK: ret i32 [[RESULT]]
47f4a2713aSLionel Sambuc }
48f4a2713aSLionel Sambuc
aligned_int(void)49f4a2713aSLionel Sambuc __int128 aligned_int(void) {
50f4a2713aSLionel Sambuc // CHECK-LABEL: define i128 @aligned_int
51f4a2713aSLionel Sambuc return va_arg(the_list, __int128);
52f4a2713aSLionel Sambuc // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 3)
53f4a2713aSLionel Sambuc // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
54f4a2713aSLionel Sambuc // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
55f4a2713aSLionel Sambuc
56f4a2713aSLionel Sambuc // CHECK: [[VAARG_MAYBE_REG]]
57f4a2713aSLionel Sambuc // CHECK: [[ALIGN_REGOFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 15
58f4a2713aSLionel Sambuc // CHECK: [[ALIGNED_REGOFFS:%[a-z_0-9]+]] = and i32 [[ALIGN_REGOFFS]], -16
59f4a2713aSLionel Sambuc // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[ALIGNED_REGOFFS]], 16
60f4a2713aSLionel Sambuc // CHECK: store i32 [[NEW_REG_OFFS]], i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 3)
61f4a2713aSLionel Sambuc // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
62f4a2713aSLionel Sambuc // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
63f4a2713aSLionel Sambuc
64f4a2713aSLionel Sambuc // CHECK: [[VAARG_IN_REG]]
65f4a2713aSLionel Sambuc // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 1)
66f4a2713aSLionel Sambuc // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr i8* [[REG_TOP]], i32 [[ALIGNED_REGOFFS]]
67f4a2713aSLionel Sambuc // CHECK: [[FROMREG_ADDR:%[a-z_0-9]+]] = bitcast i8* [[REG_ADDR]] to i128*
68f4a2713aSLionel Sambuc // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
69f4a2713aSLionel Sambuc
70f4a2713aSLionel Sambuc // CHECK: [[VAARG_ON_STACK]]
71f4a2713aSLionel Sambuc // CHECK: [[STACK:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
72f4a2713aSLionel Sambuc // CHECK: [[STACKINT:%[a-z_0-9]+]] = ptrtoint i8* [[STACK]] to i64
73f4a2713aSLionel Sambuc // CHECK: [[ALIGN_STACK:%[a-z_0-9]+]] = add i64 [[STACKINT]], 15
74f4a2713aSLionel Sambuc // CHECK: [[ALIGNED_STACK_INT:%[a-z_0-9]+]] = and i64 [[ALIGN_STACK]], -16
75f4a2713aSLionel Sambuc // CHECK: [[ALIGNED_STACK_PTR:%[a-z_0-9]+]] = inttoptr i64 [[ALIGNED_STACK_INT]] to i8*
76f4a2713aSLionel Sambuc // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr i8* [[ALIGNED_STACK_PTR]], i32 16
77f4a2713aSLionel Sambuc // CHECK: store i8* [[NEW_STACK]], i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
78f4a2713aSLionel Sambuc // CHECK: [[FROMSTACK_ADDR:%[a-z_0-9]+]] = bitcast i8* [[ALIGNED_STACK_PTR]] to i128*
79f4a2713aSLionel Sambuc // CHECK: br label %[[VAARG_END]]
80f4a2713aSLionel Sambuc
81f4a2713aSLionel Sambuc // CHECK: [[VAARG_END]]
82f4a2713aSLionel Sambuc // CHECK: [[ADDR:%[a-z._0-9]+]] = phi i128* [ [[FROMREG_ADDR]], %[[VAARG_IN_REG]] ], [ [[FROMSTACK_ADDR]], %[[VAARG_ON_STACK]] ]
83f4a2713aSLionel Sambuc // CHECK: [[RESULT:%[a-z_0-9]+]] = load i128* [[ADDR]]
84f4a2713aSLionel Sambuc // CHECK: ret i128 [[RESULT]]
85f4a2713aSLionel Sambuc }
86f4a2713aSLionel Sambuc
87f4a2713aSLionel Sambuc struct bigstruct {
88f4a2713aSLionel Sambuc int a[10];
89f4a2713aSLionel Sambuc };
90f4a2713aSLionel Sambuc
simple_indirect(void)91f4a2713aSLionel Sambuc struct bigstruct simple_indirect(void) {
92f4a2713aSLionel Sambuc // CHECK-LABEL: define void @simple_indirect
93f4a2713aSLionel Sambuc return va_arg(the_list, struct bigstruct);
94f4a2713aSLionel Sambuc // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 3)
95f4a2713aSLionel Sambuc // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
96f4a2713aSLionel Sambuc // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
97f4a2713aSLionel Sambuc
98f4a2713aSLionel Sambuc // CHECK: [[VAARG_MAYBE_REG]]
99f4a2713aSLionel Sambuc // CHECK-NOT: and i32
100f4a2713aSLionel Sambuc // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
101f4a2713aSLionel Sambuc // CHECK: store i32 [[NEW_REG_OFFS]], i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 3)
102f4a2713aSLionel Sambuc // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
103f4a2713aSLionel Sambuc // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
104f4a2713aSLionel Sambuc
105f4a2713aSLionel Sambuc // CHECK: [[VAARG_IN_REG]]
106f4a2713aSLionel Sambuc // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 1)
107f4a2713aSLionel Sambuc // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr i8* [[REG_TOP]], i32 [[GR_OFFS]]
108f4a2713aSLionel Sambuc // CHECK: [[FROMREG_ADDR:%[a-z_0-9]+]] = bitcast i8* [[REG_ADDR]] to %struct.bigstruct**
109f4a2713aSLionel Sambuc // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
110f4a2713aSLionel Sambuc
111f4a2713aSLionel Sambuc // CHECK: [[VAARG_ON_STACK]]
112f4a2713aSLionel Sambuc // CHECK: [[STACK:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
113f4a2713aSLionel Sambuc // CHECK-NOT: and i64
114f4a2713aSLionel Sambuc // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr i8* [[STACK]], i32 8
115f4a2713aSLionel Sambuc // CHECK: store i8* [[NEW_STACK]], i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
116f4a2713aSLionel Sambuc // CHECK: [[FROMSTACK_ADDR:%[a-z_0-9]+]] = bitcast i8* [[STACK]] to %struct.bigstruct**
117f4a2713aSLionel Sambuc // CHECK: br label %[[VAARG_END]]
118f4a2713aSLionel Sambuc
119f4a2713aSLionel Sambuc // CHECK: [[VAARG_END]]
120f4a2713aSLionel Sambuc // CHECK: [[ADDR:%[a-z._0-9]+]] = phi %struct.bigstruct** [ [[FROMREG_ADDR]], %[[VAARG_IN_REG]] ], [ [[FROMSTACK_ADDR]], %[[VAARG_ON_STACK]] ]
121f4a2713aSLionel Sambuc // CHECK: load %struct.bigstruct** [[ADDR]]
122f4a2713aSLionel Sambuc }
123f4a2713aSLionel Sambuc
124f4a2713aSLionel Sambuc struct aligned_bigstruct {
125f4a2713aSLionel Sambuc float a;
126f4a2713aSLionel Sambuc long double b;
127f4a2713aSLionel Sambuc };
128f4a2713aSLionel Sambuc
simple_aligned_indirect(void)129f4a2713aSLionel Sambuc struct aligned_bigstruct simple_aligned_indirect(void) {
130f4a2713aSLionel Sambuc // CHECK-LABEL: define void @simple_aligned_indirect
131f4a2713aSLionel Sambuc return va_arg(the_list, struct aligned_bigstruct);
132f4a2713aSLionel Sambuc // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 3)
133f4a2713aSLionel Sambuc // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
134f4a2713aSLionel Sambuc // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
135f4a2713aSLionel Sambuc
136f4a2713aSLionel Sambuc // CHECK: [[VAARG_MAYBE_REG]]
137f4a2713aSLionel Sambuc // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
138f4a2713aSLionel Sambuc // CHECK: store i32 [[NEW_REG_OFFS]], i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 3)
139f4a2713aSLionel Sambuc // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
140f4a2713aSLionel Sambuc // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
141f4a2713aSLionel Sambuc
142f4a2713aSLionel Sambuc // CHECK: [[VAARG_IN_REG]]
143f4a2713aSLionel Sambuc // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 1)
144f4a2713aSLionel Sambuc // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr i8* [[REG_TOP]], i32 [[GR_OFFS]]
145f4a2713aSLionel Sambuc // CHECK: [[FROMREG_ADDR:%[a-z_0-9]+]] = bitcast i8* [[REG_ADDR]] to %struct.aligned_bigstruct**
146f4a2713aSLionel Sambuc // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
147f4a2713aSLionel Sambuc
148f4a2713aSLionel Sambuc // CHECK: [[VAARG_ON_STACK]]
149f4a2713aSLionel Sambuc // CHECK: [[STACK:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
150f4a2713aSLionel Sambuc // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr i8* [[STACK]], i32 8
151f4a2713aSLionel Sambuc // CHECK: store i8* [[NEW_STACK]], i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
152f4a2713aSLionel Sambuc // CHECK: [[FROMSTACK_ADDR:%[a-z_0-9]+]] = bitcast i8* [[STACK]] to %struct.aligned_bigstruct**
153f4a2713aSLionel Sambuc // CHECK: br label %[[VAARG_END]]
154f4a2713aSLionel Sambuc
155f4a2713aSLionel Sambuc // CHECK: [[VAARG_END]]
156f4a2713aSLionel Sambuc // CHECK: [[ADDR:%[a-z._0-9]+]] = phi %struct.aligned_bigstruct** [ [[FROMREG_ADDR]], %[[VAARG_IN_REG]] ], [ [[FROMSTACK_ADDR]], %[[VAARG_ON_STACK]] ]
157f4a2713aSLionel Sambuc // CHECK: load %struct.aligned_bigstruct** [[ADDR]]
158f4a2713aSLionel Sambuc }
159f4a2713aSLionel Sambuc
simple_double(void)160f4a2713aSLionel Sambuc double simple_double(void) {
161f4a2713aSLionel Sambuc // CHECK-LABEL: define double @simple_double
162f4a2713aSLionel Sambuc return va_arg(the_list, double);
163f4a2713aSLionel Sambuc // CHECK: [[VR_OFFS:%[a-z_0-9]+]] = load i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 4)
164f4a2713aSLionel Sambuc // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[VR_OFFS]], 0
165*0a6a1f1dSLionel Sambuc // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG]]
166f4a2713aSLionel Sambuc
167f4a2713aSLionel Sambuc // CHECK: [[VAARG_MAYBE_REG]]
168f4a2713aSLionel Sambuc // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[VR_OFFS]], 16
169f4a2713aSLionel Sambuc // CHECK: store i32 [[NEW_REG_OFFS]], i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 4)
170f4a2713aSLionel Sambuc // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
171f4a2713aSLionel Sambuc // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
172f4a2713aSLionel Sambuc
173f4a2713aSLionel Sambuc // CHECK: [[VAARG_IN_REG]]
174f4a2713aSLionel Sambuc // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 2)
175f4a2713aSLionel Sambuc // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr i8* [[REG_TOP]], i32 [[VR_OFFS]]
176*0a6a1f1dSLionel Sambuc // CHECK-BE: [[REG_ADDR_VAL:%[0-9]+]] = ptrtoint i8* [[REG_ADDR]] to i64
177*0a6a1f1dSLionel Sambuc // CHECK-BE: [[REG_ADDR_VAL_ALIGNED:%[a-z_0-9]*]] = add i64 [[REG_ADDR_VAL]], 8
178*0a6a1f1dSLionel Sambuc // CHECK-BE: [[REG_ADDR:%[0-9]+]] = inttoptr i64 [[REG_ADDR_VAL_ALIGNED]] to i8*
179f4a2713aSLionel Sambuc // CHECK: [[FROMREG_ADDR:%[a-z_0-9]+]] = bitcast i8* [[REG_ADDR]] to double*
180*0a6a1f1dSLionel Sambuc // CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
181f4a2713aSLionel Sambuc
182f4a2713aSLionel Sambuc // CHECK: [[VAARG_ON_STACK]]
183f4a2713aSLionel Sambuc // CHECK: [[STACK:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
184f4a2713aSLionel Sambuc // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr i8* [[STACK]], i32 8
185f4a2713aSLionel Sambuc // CHECK: store i8* [[NEW_STACK]], i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
186f4a2713aSLionel Sambuc // CHECK: [[FROMSTACK_ADDR:%[a-z_0-9]+]] = bitcast i8* [[STACK]] to double*
187f4a2713aSLionel Sambuc // CHECK: br label %[[VAARG_END]]
188f4a2713aSLionel Sambuc
189f4a2713aSLionel Sambuc // CHECK: [[VAARG_END]]
190f4a2713aSLionel Sambuc // CHECK: [[ADDR:%[a-z._0-9]+]] = phi double* [ [[FROMREG_ADDR]], %[[VAARG_IN_REG]] ], [ [[FROMSTACK_ADDR]], %[[VAARG_ON_STACK]] ]
191f4a2713aSLionel Sambuc // CHECK: [[RESULT:%[a-z_0-9]+]] = load double* [[ADDR]]
192f4a2713aSLionel Sambuc // CHECK: ret double [[RESULT]]
193f4a2713aSLionel Sambuc }
194f4a2713aSLionel Sambuc
195f4a2713aSLionel Sambuc struct hfa {
196f4a2713aSLionel Sambuc float a, b;
197f4a2713aSLionel Sambuc };
198f4a2713aSLionel Sambuc
simple_hfa(void)199f4a2713aSLionel Sambuc struct hfa simple_hfa(void) {
200f4a2713aSLionel Sambuc // CHECK-LABEL: define %struct.hfa @simple_hfa
201f4a2713aSLionel Sambuc return va_arg(the_list, struct hfa);
202f4a2713aSLionel Sambuc // CHECK: [[VR_OFFS:%[a-z_0-9]+]] = load i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 4)
203f4a2713aSLionel Sambuc // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[VR_OFFS]], 0
204f4a2713aSLionel Sambuc // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
205f4a2713aSLionel Sambuc
206f4a2713aSLionel Sambuc // CHECK: [[VAARG_MAYBE_REG]]
207f4a2713aSLionel Sambuc // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[VR_OFFS]], 32
208f4a2713aSLionel Sambuc // CHECK: store i32 [[NEW_REG_OFFS]], i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 4)
209f4a2713aSLionel Sambuc // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
210f4a2713aSLionel Sambuc // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
211f4a2713aSLionel Sambuc
212f4a2713aSLionel Sambuc // CHECK: [[VAARG_IN_REG]]
213f4a2713aSLionel Sambuc // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 2)
214f4a2713aSLionel Sambuc // CHECK: [[FIRST_REG:%[a-z_0-9]+]] = getelementptr i8* [[REG_TOP]], i32 [[VR_OFFS]]
215*0a6a1f1dSLionel Sambuc // CHECK-LE: [[EL_ADDR:%[a-z_0-9]+]] = getelementptr i8* [[FIRST_REG]], i32 0
216*0a6a1f1dSLionel Sambuc // CHECK-BE: [[EL_ADDR:%[a-z_0-9]+]] = getelementptr i8* [[FIRST_REG]], i32 12
217f4a2713aSLionel Sambuc // CHECK: [[EL_TYPED:%[a-z_0-9]+]] = bitcast i8* [[EL_ADDR]] to float*
218f4a2713aSLionel Sambuc // CHECK: [[EL_TMPADDR:%[a-z_0-9]+]] = getelementptr inbounds [2 x float]* %[[TMP_HFA:[a-z_.0-9]+]], i32 0, i32 0
219f4a2713aSLionel Sambuc // CHECK: [[EL:%[a-z_0-9]+]] = load float* [[EL_TYPED]]
220f4a2713aSLionel Sambuc // CHECK: store float [[EL]], float* [[EL_TMPADDR]]
221*0a6a1f1dSLionel Sambuc // CHECK-LE: [[EL_ADDR:%[a-z_0-9]+]] = getelementptr i8* [[FIRST_REG]], i32 16
222*0a6a1f1dSLionel Sambuc // CHECK-BE: [[EL_ADDR:%[a-z_0-9]+]] = getelementptr i8* [[FIRST_REG]], i32 28
223f4a2713aSLionel Sambuc // CHECK: [[EL_TYPED:%[a-z_0-9]+]] = bitcast i8* [[EL_ADDR]] to float*
224f4a2713aSLionel Sambuc // CHECK: [[EL_TMPADDR:%[a-z_0-9]+]] = getelementptr inbounds [2 x float]* %[[TMP_HFA]], i32 0, i32 1
225f4a2713aSLionel Sambuc // CHECK: [[EL:%[a-z_0-9]+]] = load float* [[EL_TYPED]]
226f4a2713aSLionel Sambuc // CHECK: store float [[EL]], float* [[EL_TMPADDR]]
227f4a2713aSLionel Sambuc // CHECK: [[FROMREG_ADDR:%[a-z_0-9]+]] = bitcast [2 x float]* %[[TMP_HFA]] to %struct.hfa*
228f4a2713aSLionel Sambuc // CHECK: br label %[[VAARG_END:[a-z_.0-9]+]]
229f4a2713aSLionel Sambuc
230f4a2713aSLionel Sambuc // CHECK: [[VAARG_ON_STACK]]
231f4a2713aSLionel Sambuc // CHECK: [[STACK:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
232f4a2713aSLionel Sambuc // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr i8* [[STACK]], i32 8
233f4a2713aSLionel Sambuc // CHECK: store i8* [[NEW_STACK]], i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
234f4a2713aSLionel Sambuc // CHECK: [[FROMSTACK_ADDR:%[a-z_0-9]+]] = bitcast i8* [[STACK]] to %struct.hfa*
235f4a2713aSLionel Sambuc // CHECK: br label %[[VAARG_END]]
236f4a2713aSLionel Sambuc
237f4a2713aSLionel Sambuc // CHECK: [[VAARG_END]]
238f4a2713aSLionel Sambuc // CHECK: [[ADDR:%[a-z._0-9]+]] = phi %struct.hfa* [ [[FROMREG_ADDR]], %[[VAARG_IN_REG]] ], [ [[FROMSTACK_ADDR]], %[[VAARG_ON_STACK]] ]
239f4a2713aSLionel Sambuc }
240f4a2713aSLionel Sambuc
check_start(int n,...)241f4a2713aSLionel Sambuc void check_start(int n, ...) {
242f4a2713aSLionel Sambuc // CHECK-LABEL: define void @check_start(i32 %n, ...)
243f4a2713aSLionel Sambuc
244f4a2713aSLionel Sambuc va_list the_list;
245f4a2713aSLionel Sambuc va_start(the_list, n);
246f4a2713aSLionel Sambuc // CHECK: [[THE_LIST:%[a-z_0-9]+]] = alloca %struct.__va_list
247f4a2713aSLionel Sambuc // CHECK: [[VOIDP_THE_LIST:%[a-z_0-9]+]] = bitcast %struct.__va_list* [[THE_LIST]] to i8*
248f4a2713aSLionel Sambuc // CHECK: call void @llvm.va_start(i8* [[VOIDP_THE_LIST]])
249f4a2713aSLionel Sambuc }
250f4a2713aSLionel Sambuc
251f4a2713aSLionel Sambuc
252