xref: /llvm-project/clang/test/CodeGenCXX/x86_64-vaarg.cpp (revision a27f40e5d9636b0853e8de0b95d72261f8d34696)
1631248dcShstk30-hw // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
2631248dcShstk30-hw // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
3631248dcShstk30-hw 
4631248dcShstk30-hw typedef struct { struct {} a; } empty;
5631248dcShstk30-hw 
69c8dd5e6SLongsheng Mou // CHECK-LABEL: @_Z17empty_record_testiz(
7631248dcShstk30-hw // CHECK-NEXT:  entry:
8631248dcShstk30-hw // CHECK-NEXT:    [[Z_ADDR:%.*]] = alloca i32, align 4
9631248dcShstk30-hw // CHECK-NEXT:    [[LIST:%.*]] = alloca [1 x %struct.__va_list_tag], align 16
10631248dcShstk30-hw // CHECK-NEXT:    store i32 [[Z:%.*]], ptr [[Z_ADDR]], align 4
11631248dcShstk30-hw // CHECK-NEXT:    [[ARRAYDECAY:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0
12ab7dba23SAlex Voicu // CHECK-NEXT:    call void @llvm.va_start.p0(ptr [[ARRAYDECAY]])
13631248dcShstk30-hw // CHECK-NEXT:    [[ARRAYDECAY1:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0
14631248dcShstk30-hw // CHECK-NEXT:    ret void
159c8dd5e6SLongsheng Mou //
16631248dcShstk30-hw empty empty_record_test(int z, ...) {
17631248dcShstk30-hw   __builtin_va_list list;
18631248dcShstk30-hw   __builtin_va_start(list, z);
19631248dcShstk30-hw   return __builtin_va_arg(list, empty);
20631248dcShstk30-hw }
219c8dd5e6SLongsheng Mou 
229c8dd5e6SLongsheng Mou typedef struct {
239c8dd5e6SLongsheng Mou   struct{} a;
249c8dd5e6SLongsheng Mou   double b;
259c8dd5e6SLongsheng Mou } s1;
269c8dd5e6SLongsheng Mou 
279c8dd5e6SLongsheng Mou // CHECK-LABEL: @_Z1fiz(
289c8dd5e6SLongsheng Mou // CHECK-NEXT:  entry:
299c8dd5e6SLongsheng Mou // CHECK-NEXT:    [[RETVAL:%.*]] = alloca [[STRUCT_S1:%.*]], align 8
309c8dd5e6SLongsheng Mou // CHECK-NEXT:    [[Z_ADDR:%.*]] = alloca i32, align 4
319c8dd5e6SLongsheng Mou // CHECK-NEXT:    [[LIST:%.*]] = alloca [1 x %struct.__va_list_tag], align 16
32*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP:%.*]] = alloca [[STRUCT_S1]], align 8
339c8dd5e6SLongsheng Mou // CHECK-NEXT:    store i32 [[Z:%.*]], ptr [[Z_ADDR]], align 4
349c8dd5e6SLongsheng Mou // CHECK-NEXT:    [[ARRAYDECAY:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0
35ab7dba23SAlex Voicu // CHECK-NEXT:    call void @llvm.va_start.p0(ptr [[ARRAYDECAY]])
369c8dd5e6SLongsheng Mou // CHECK-NEXT:    [[ARRAYDECAY1:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0
3794473f4dSHari Limaye // CHECK-NEXT:    [[FP_OFFSET_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG:%.*]], ptr [[ARRAYDECAY1]], i32 0, i32 1
389c8dd5e6SLongsheng Mou // CHECK-NEXT:    [[FP_OFFSET:%.*]] = load i32, ptr [[FP_OFFSET_P]], align 4
399c8dd5e6SLongsheng Mou // CHECK-NEXT:    [[FITS_IN_FP:%.*]] = icmp ule i32 [[FP_OFFSET]], 160
409c8dd5e6SLongsheng Mou // CHECK-NEXT:    br i1 [[FITS_IN_FP]], label [[VAARG_IN_REG:%.*]], label [[VAARG_IN_MEM:%.*]]
419c8dd5e6SLongsheng Mou // CHECK:       vaarg.in_reg:
4294473f4dSHari Limaye // CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 3
439c8dd5e6SLongsheng Mou // CHECK-NEXT:    [[REG_SAVE_AREA:%.*]] = load ptr, ptr [[TMP0]], align 16
449c8dd5e6SLongsheng Mou // CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i8, ptr [[REG_SAVE_AREA]], i32 [[FP_OFFSET]]
45*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP2:%.*]] = load double, ptr [[TMP1]], align 8
46*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP3:%.*]] = getelementptr i8, ptr [[TMP]], i32 8
47*a27f40e5SLongsheng Mou // CHECK-NEXT:    store double [[TMP2]], ptr [[TMP3]], align 8
48*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP4:%.*]] = add i32 [[FP_OFFSET]], 16
49*a27f40e5SLongsheng Mou // CHECK-NEXT:    store i32 [[TMP4]], ptr [[FP_OFFSET_P]], align 4
509c8dd5e6SLongsheng Mou // CHECK-NEXT:    br label [[VAARG_END:%.*]]
519c8dd5e6SLongsheng Mou // CHECK:       vaarg.in_mem:
5294473f4dSHari Limaye // CHECK-NEXT:    [[OVERFLOW_ARG_AREA_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 2
539c8dd5e6SLongsheng Mou // CHECK-NEXT:    [[OVERFLOW_ARG_AREA:%.*]] = load ptr, ptr [[OVERFLOW_ARG_AREA_P]], align 8
549c8dd5e6SLongsheng Mou // CHECK-NEXT:    [[OVERFLOW_ARG_AREA_NEXT:%.*]] = getelementptr i8, ptr [[OVERFLOW_ARG_AREA]], i32 16
559c8dd5e6SLongsheng Mou // CHECK-NEXT:    store ptr [[OVERFLOW_ARG_AREA_NEXT]], ptr [[OVERFLOW_ARG_AREA_P]], align 8
569c8dd5e6SLongsheng Mou // CHECK-NEXT:    br label [[VAARG_END]]
579c8dd5e6SLongsheng Mou // CHECK:       vaarg.end:
58*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[VAARG_ADDR:%.*]] = phi ptr [ [[TMP]], [[VAARG_IN_REG]] ], [ [[OVERFLOW_ARG_AREA]], [[VAARG_IN_MEM]] ]
599c8dd5e6SLongsheng Mou // CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL]], ptr align 8 [[VAARG_ADDR]], i64 16, i1 false)
60*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[RETVAL]], i64 8
61*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP6:%.*]] = load double, ptr [[TMP5]], align 8
62*a27f40e5SLongsheng Mou // CHECK-NEXT:    ret double [[TMP6]]
639c8dd5e6SLongsheng Mou //
649c8dd5e6SLongsheng Mou s1 f(int z, ...) {
659c8dd5e6SLongsheng Mou   __builtin_va_list list;
669c8dd5e6SLongsheng Mou   __builtin_va_start(list, z);
679c8dd5e6SLongsheng Mou   return __builtin_va_arg(list, s1);
689c8dd5e6SLongsheng Mou }
69*a27f40e5SLongsheng Mou 
70*a27f40e5SLongsheng Mou typedef struct {
71*a27f40e5SLongsheng Mou   struct{} a[5];
72*a27f40e5SLongsheng Mou   float b;
73*a27f40e5SLongsheng Mou   float c;
74*a27f40e5SLongsheng Mou } s2;
75*a27f40e5SLongsheng Mou 
76*a27f40e5SLongsheng Mou // CHECK-LABEL: @_Z2f2iz(
77*a27f40e5SLongsheng Mou // CHECK-NEXT:  entry:
78*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[RETVAL:%.*]] = alloca [[STRUCT_S2:%.*]], align 4
79*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[Z_ADDR:%.*]] = alloca i32, align 4
80*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[LIST:%.*]] = alloca [1 x %struct.__va_list_tag], align 16
81*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP:%.*]] = alloca [[STRUCT_S2]], align 4
82*a27f40e5SLongsheng Mou // CHECK-NEXT:    store i32 [[Z:%.*]], ptr [[Z_ADDR]], align 4
83*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[ARRAYDECAY:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0
84*a27f40e5SLongsheng Mou // CHECK-NEXT:    call void @llvm.va_start.p0(ptr [[ARRAYDECAY]])
85*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[ARRAYDECAY1:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0
86*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[FP_OFFSET_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG:%.*]], ptr [[ARRAYDECAY1]], i32 0, i32 1
87*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[FP_OFFSET:%.*]] = load i32, ptr [[FP_OFFSET_P]], align 4
88*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[FITS_IN_FP:%.*]] = icmp ule i32 [[FP_OFFSET]], 160
89*a27f40e5SLongsheng Mou // CHECK-NEXT:    br i1 [[FITS_IN_FP]], label [[VAARG_IN_REG:%.*]], label [[VAARG_IN_MEM:%.*]]
90*a27f40e5SLongsheng Mou // CHECK:       vaarg.in_reg:
91*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 3
92*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[REG_SAVE_AREA:%.*]] = load ptr, ptr [[TMP0]], align 16
93*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i8, ptr [[REG_SAVE_AREA]], i32 [[FP_OFFSET]]
94*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP2:%.*]] = load <2 x float>, ptr [[TMP1]], align 4
95*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP3:%.*]] = getelementptr i8, ptr [[TMP]], i32 8
96*a27f40e5SLongsheng Mou // CHECK-NEXT:    store <2 x float> [[TMP2]], ptr [[TMP3]], align 4
97*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP4:%.*]] = add i32 [[FP_OFFSET]], 16
98*a27f40e5SLongsheng Mou // CHECK-NEXT:    store i32 [[TMP4]], ptr [[FP_OFFSET_P]], align 4
99*a27f40e5SLongsheng Mou // CHECK-NEXT:    br label [[VAARG_END:%.*]]
100*a27f40e5SLongsheng Mou // CHECK:       vaarg.in_mem:
101*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[OVERFLOW_ARG_AREA_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 2
102*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[OVERFLOW_ARG_AREA:%.*]] = load ptr, ptr [[OVERFLOW_ARG_AREA_P]], align 8
103*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[OVERFLOW_ARG_AREA_NEXT:%.*]] = getelementptr i8, ptr [[OVERFLOW_ARG_AREA]], i32 16
104*a27f40e5SLongsheng Mou // CHECK-NEXT:    store ptr [[OVERFLOW_ARG_AREA_NEXT]], ptr [[OVERFLOW_ARG_AREA_P]], align 8
105*a27f40e5SLongsheng Mou // CHECK-NEXT:    br label [[VAARG_END]]
106*a27f40e5SLongsheng Mou // CHECK:       vaarg.end:
107*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[VAARG_ADDR:%.*]] = phi ptr [ [[TMP]], [[VAARG_IN_REG]] ], [ [[OVERFLOW_ARG_AREA]], [[VAARG_IN_MEM]] ]
108*a27f40e5SLongsheng Mou // CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[RETVAL]], ptr align 4 [[VAARG_ADDR]], i64 16, i1 false)
109*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[RETVAL]], i64 8
110*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP6:%.*]] = load <2 x float>, ptr [[TMP5]], align 4
111*a27f40e5SLongsheng Mou // CHECK-NEXT:    ret <2 x float> [[TMP6]]
112*a27f40e5SLongsheng Mou //
113*a27f40e5SLongsheng Mou s2 f2(int z, ...) {
114*a27f40e5SLongsheng Mou   __builtin_va_list list;
115*a27f40e5SLongsheng Mou   __builtin_va_start(list, z);
116*a27f40e5SLongsheng Mou   return __builtin_va_arg(list, s2);
117*a27f40e5SLongsheng Mou }
118*a27f40e5SLongsheng Mou 
119*a27f40e5SLongsheng Mou typedef struct {
120*a27f40e5SLongsheng Mou   struct{} a;
121*a27f40e5SLongsheng Mou   long long b;
122*a27f40e5SLongsheng Mou } s3;
123*a27f40e5SLongsheng Mou 
124*a27f40e5SLongsheng Mou // CHECK-LABEL: @_Z2f3iz(
125*a27f40e5SLongsheng Mou // CHECK-NEXT:  entry:
126*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[RETVAL:%.*]] = alloca [[STRUCT_S3:%.*]], align 8
127*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[Z_ADDR:%.*]] = alloca i32, align 4
128*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[LIST:%.*]] = alloca [1 x %struct.__va_list_tag], align 16
129*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP:%.*]] = alloca [[STRUCT_S3]], align 8
130*a27f40e5SLongsheng Mou // CHECK-NEXT:    store i32 [[Z:%.*]], ptr [[Z_ADDR]], align 4
131*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[ARRAYDECAY:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0
132*a27f40e5SLongsheng Mou // CHECK-NEXT:    call void @llvm.va_start.p0(ptr [[ARRAYDECAY]])
133*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[ARRAYDECAY1:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0
134*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[GP_OFFSET_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG:%.*]], ptr [[ARRAYDECAY1]], i32 0, i32 0
135*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[GP_OFFSET:%.*]] = load i32, ptr [[GP_OFFSET_P]], align 16
136*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[FITS_IN_GP:%.*]] = icmp ule i32 [[GP_OFFSET]], 40
137*a27f40e5SLongsheng Mou // CHECK-NEXT:    br i1 [[FITS_IN_GP]], label [[VAARG_IN_REG:%.*]], label [[VAARG_IN_MEM:%.*]]
138*a27f40e5SLongsheng Mou // CHECK:       vaarg.in_reg:
139*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 3
140*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[REG_SAVE_AREA:%.*]] = load ptr, ptr [[TMP0]], align 16
141*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i8, ptr [[REG_SAVE_AREA]], i32 [[GP_OFFSET]]
142*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 8
143*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP3:%.*]] = getelementptr i8, ptr [[TMP]], i32 8
144*a27f40e5SLongsheng Mou // CHECK-NEXT:    store i64 [[TMP2]], ptr [[TMP3]], align 8
145*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP4:%.*]] = add i32 [[GP_OFFSET]], 8
146*a27f40e5SLongsheng Mou // CHECK-NEXT:    store i32 [[TMP4]], ptr [[GP_OFFSET_P]], align 16
147*a27f40e5SLongsheng Mou // CHECK-NEXT:    br label [[VAARG_END:%.*]]
148*a27f40e5SLongsheng Mou // CHECK:       vaarg.in_mem:
149*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[OVERFLOW_ARG_AREA_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 2
150*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[OVERFLOW_ARG_AREA:%.*]] = load ptr, ptr [[OVERFLOW_ARG_AREA_P]], align 8
151*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[OVERFLOW_ARG_AREA_NEXT:%.*]] = getelementptr i8, ptr [[OVERFLOW_ARG_AREA]], i32 16
152*a27f40e5SLongsheng Mou // CHECK-NEXT:    store ptr [[OVERFLOW_ARG_AREA_NEXT]], ptr [[OVERFLOW_ARG_AREA_P]], align 8
153*a27f40e5SLongsheng Mou // CHECK-NEXT:    br label [[VAARG_END]]
154*a27f40e5SLongsheng Mou // CHECK:       vaarg.end:
155*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[VAARG_ADDR:%.*]] = phi ptr [ [[TMP]], [[VAARG_IN_REG]] ], [ [[OVERFLOW_ARG_AREA]], [[VAARG_IN_MEM]] ]
156*a27f40e5SLongsheng Mou // CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL]], ptr align 8 [[VAARG_ADDR]], i64 16, i1 false)
157*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[RETVAL]], i64 8
158*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP6:%.*]] = load i64, ptr [[TMP5]], align 8
159*a27f40e5SLongsheng Mou // CHECK-NEXT:    ret i64 [[TMP6]]
160*a27f40e5SLongsheng Mou //
161*a27f40e5SLongsheng Mou s3 f3(int z, ...) {
162*a27f40e5SLongsheng Mou   __builtin_va_list list;
163*a27f40e5SLongsheng Mou   __builtin_va_start(list, z);
164*a27f40e5SLongsheng Mou   return __builtin_va_arg(list, s3);
165*a27f40e5SLongsheng Mou }
166*a27f40e5SLongsheng Mou 
167*a27f40e5SLongsheng Mou typedef struct {
168*a27f40e5SLongsheng Mou   struct{} a[7];
169*a27f40e5SLongsheng Mou   short b;
170*a27f40e5SLongsheng Mou   int c;
171*a27f40e5SLongsheng Mou } s4;
172*a27f40e5SLongsheng Mou 
173*a27f40e5SLongsheng Mou // CHECK-LABEL: @_Z2f4iz(
174*a27f40e5SLongsheng Mou // CHECK-NEXT:  entry:
175*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[RETVAL:%.*]] = alloca [[STRUCT_S4:%.*]], align 4
176*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[Z_ADDR:%.*]] = alloca i32, align 4
177*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[LIST:%.*]] = alloca [1 x %struct.__va_list_tag], align 16
178*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP:%.*]] = alloca [[STRUCT_S4]], align 4
179*a27f40e5SLongsheng Mou // CHECK-NEXT:    store i32 [[Z:%.*]], ptr [[Z_ADDR]], align 4
180*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[ARRAYDECAY:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0
181*a27f40e5SLongsheng Mou // CHECK-NEXT:    call void @llvm.va_start.p0(ptr [[ARRAYDECAY]])
182*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[ARRAYDECAY1:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0
183*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[GP_OFFSET_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG:%.*]], ptr [[ARRAYDECAY1]], i32 0, i32 0
184*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[GP_OFFSET:%.*]] = load i32, ptr [[GP_OFFSET_P]], align 16
185*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[FITS_IN_GP:%.*]] = icmp ule i32 [[GP_OFFSET]], 40
186*a27f40e5SLongsheng Mou // CHECK-NEXT:    br i1 [[FITS_IN_GP]], label [[VAARG_IN_REG:%.*]], label [[VAARG_IN_MEM:%.*]]
187*a27f40e5SLongsheng Mou // CHECK:       vaarg.in_reg:
188*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 3
189*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[REG_SAVE_AREA:%.*]] = load ptr, ptr [[TMP0]], align 16
190*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i8, ptr [[REG_SAVE_AREA]], i32 [[GP_OFFSET]]
191*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 4
192*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP3:%.*]] = getelementptr i8, ptr [[TMP]], i32 8
193*a27f40e5SLongsheng Mou // CHECK-NEXT:    store i64 [[TMP2]], ptr [[TMP3]], align 4
194*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP4:%.*]] = add i32 [[GP_OFFSET]], 8
195*a27f40e5SLongsheng Mou // CHECK-NEXT:    store i32 [[TMP4]], ptr [[GP_OFFSET_P]], align 16
196*a27f40e5SLongsheng Mou // CHECK-NEXT:    br label [[VAARG_END:%.*]]
197*a27f40e5SLongsheng Mou // CHECK:       vaarg.in_mem:
198*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[OVERFLOW_ARG_AREA_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 2
199*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[OVERFLOW_ARG_AREA:%.*]] = load ptr, ptr [[OVERFLOW_ARG_AREA_P]], align 8
200*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[OVERFLOW_ARG_AREA_NEXT:%.*]] = getelementptr i8, ptr [[OVERFLOW_ARG_AREA]], i32 16
201*a27f40e5SLongsheng Mou // CHECK-NEXT:    store ptr [[OVERFLOW_ARG_AREA_NEXT]], ptr [[OVERFLOW_ARG_AREA_P]], align 8
202*a27f40e5SLongsheng Mou // CHECK-NEXT:    br label [[VAARG_END]]
203*a27f40e5SLongsheng Mou // CHECK:       vaarg.end:
204*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[VAARG_ADDR:%.*]] = phi ptr [ [[TMP]], [[VAARG_IN_REG]] ], [ [[OVERFLOW_ARG_AREA]], [[VAARG_IN_MEM]] ]
205*a27f40e5SLongsheng Mou // CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[RETVAL]], ptr align 4 [[VAARG_ADDR]], i64 16, i1 false)
206*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[RETVAL]], i64 8
207*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP6:%.*]] = load i64, ptr [[TMP5]], align 4
208*a27f40e5SLongsheng Mou // CHECK-NEXT:    ret i64 [[TMP6]]
209*a27f40e5SLongsheng Mou //
210*a27f40e5SLongsheng Mou s4 f4(int z, ...) {
211*a27f40e5SLongsheng Mou   __builtin_va_list list;
212*a27f40e5SLongsheng Mou   __builtin_va_start(list, z);
213*a27f40e5SLongsheng Mou   return __builtin_va_arg(list, s4);
214*a27f40e5SLongsheng Mou }
215*a27f40e5SLongsheng Mou 
216*a27f40e5SLongsheng Mou typedef struct {
217*a27f40e5SLongsheng Mou   struct{} a[5];
218*a27f40e5SLongsheng Mou   float b;
219*a27f40e5SLongsheng Mou   int c;
220*a27f40e5SLongsheng Mou } s5;
221*a27f40e5SLongsheng Mou 
222*a27f40e5SLongsheng Mou // CHECK-LABEL: @_Z2f5iz(
223*a27f40e5SLongsheng Mou // CHECK-NEXT:  entry:
224*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[RETVAL:%.*]] = alloca [[STRUCT_S5:%.*]], align 4
225*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[Z_ADDR:%.*]] = alloca i32, align 4
226*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[LIST:%.*]] = alloca [1 x %struct.__va_list_tag], align 16
227*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP:%.*]] = alloca [[STRUCT_S5]], align 4
228*a27f40e5SLongsheng Mou // CHECK-NEXT:    store i32 [[Z:%.*]], ptr [[Z_ADDR]], align 4
229*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[ARRAYDECAY:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0
230*a27f40e5SLongsheng Mou // CHECK-NEXT:    call void @llvm.va_start.p0(ptr [[ARRAYDECAY]])
231*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[ARRAYDECAY1:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0
232*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[GP_OFFSET_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG:%.*]], ptr [[ARRAYDECAY1]], i32 0, i32 0
233*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[GP_OFFSET:%.*]] = load i32, ptr [[GP_OFFSET_P]], align 16
234*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[FITS_IN_GP:%.*]] = icmp ule i32 [[GP_OFFSET]], 40
235*a27f40e5SLongsheng Mou // CHECK-NEXT:    br i1 [[FITS_IN_GP]], label [[VAARG_IN_REG:%.*]], label [[VAARG_IN_MEM:%.*]]
236*a27f40e5SLongsheng Mou // CHECK:       vaarg.in_reg:
237*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 3
238*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[REG_SAVE_AREA:%.*]] = load ptr, ptr [[TMP0]], align 16
239*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i8, ptr [[REG_SAVE_AREA]], i32 [[GP_OFFSET]]
240*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 4
241*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP3:%.*]] = getelementptr i8, ptr [[TMP]], i32 8
242*a27f40e5SLongsheng Mou // CHECK-NEXT:    store i64 [[TMP2]], ptr [[TMP3]], align 4
243*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP4:%.*]] = add i32 [[GP_OFFSET]], 8
244*a27f40e5SLongsheng Mou // CHECK-NEXT:    store i32 [[TMP4]], ptr [[GP_OFFSET_P]], align 16
245*a27f40e5SLongsheng Mou // CHECK-NEXT:    br label [[VAARG_END:%.*]]
246*a27f40e5SLongsheng Mou // CHECK:       vaarg.in_mem:
247*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[OVERFLOW_ARG_AREA_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 2
248*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[OVERFLOW_ARG_AREA:%.*]] = load ptr, ptr [[OVERFLOW_ARG_AREA_P]], align 8
249*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[OVERFLOW_ARG_AREA_NEXT:%.*]] = getelementptr i8, ptr [[OVERFLOW_ARG_AREA]], i32 16
250*a27f40e5SLongsheng Mou // CHECK-NEXT:    store ptr [[OVERFLOW_ARG_AREA_NEXT]], ptr [[OVERFLOW_ARG_AREA_P]], align 8
251*a27f40e5SLongsheng Mou // CHECK-NEXT:    br label [[VAARG_END]]
252*a27f40e5SLongsheng Mou // CHECK:       vaarg.end:
253*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[VAARG_ADDR:%.*]] = phi ptr [ [[TMP]], [[VAARG_IN_REG]] ], [ [[OVERFLOW_ARG_AREA]], [[VAARG_IN_MEM]] ]
254*a27f40e5SLongsheng Mou // CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[RETVAL]], ptr align 4 [[VAARG_ADDR]], i64 16, i1 false)
255*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[RETVAL]], i64 8
256*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP6:%.*]] = load i64, ptr [[TMP5]], align 4
257*a27f40e5SLongsheng Mou // CHECK-NEXT:    ret i64 [[TMP6]]
258*a27f40e5SLongsheng Mou //
259*a27f40e5SLongsheng Mou s5 f5(int z, ...) {
260*a27f40e5SLongsheng Mou   __builtin_va_list list;
261*a27f40e5SLongsheng Mou   __builtin_va_start(list, z);
262*a27f40e5SLongsheng Mou   return __builtin_va_arg(list, s5);
263*a27f40e5SLongsheng Mou }
264*a27f40e5SLongsheng Mou 
265*a27f40e5SLongsheng Mou typedef struct {
266*a27f40e5SLongsheng Mou   long long a;
267*a27f40e5SLongsheng Mou   struct{} b;
268*a27f40e5SLongsheng Mou } s6;
269*a27f40e5SLongsheng Mou 
270*a27f40e5SLongsheng Mou // CHECK-LABEL: @_Z2f6iz(
271*a27f40e5SLongsheng Mou // CHECK-NEXT:  entry:
272*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[RETVAL:%.*]] = alloca [[STRUCT_S6:%.*]], align 8
273*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[Z_ADDR:%.*]] = alloca i32, align 4
274*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[LIST:%.*]] = alloca [1 x %struct.__va_list_tag], align 16
275*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP:%.*]] = alloca [[STRUCT_S6]], align 8
276*a27f40e5SLongsheng Mou // CHECK-NEXT:    store i32 [[Z:%.*]], ptr [[Z_ADDR]], align 4
277*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[ARRAYDECAY:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0
278*a27f40e5SLongsheng Mou // CHECK-NEXT:    call void @llvm.va_start.p0(ptr [[ARRAYDECAY]])
279*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[ARRAYDECAY1:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0
280*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[GP_OFFSET_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG:%.*]], ptr [[ARRAYDECAY1]], i32 0, i32 0
281*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[GP_OFFSET:%.*]] = load i32, ptr [[GP_OFFSET_P]], align 16
282*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[FITS_IN_GP:%.*]] = icmp ule i32 [[GP_OFFSET]], 40
283*a27f40e5SLongsheng Mou // CHECK-NEXT:    br i1 [[FITS_IN_GP]], label [[VAARG_IN_REG:%.*]], label [[VAARG_IN_MEM:%.*]]
284*a27f40e5SLongsheng Mou // CHECK:       vaarg.in_reg:
285*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 3
286*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[REG_SAVE_AREA:%.*]] = load ptr, ptr [[TMP0]], align 16
287*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i8, ptr [[REG_SAVE_AREA]], i32 [[GP_OFFSET]]
288*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 8
289*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP3:%.*]] = getelementptr i8, ptr [[TMP]], i32 0
290*a27f40e5SLongsheng Mou // CHECK-NEXT:    store i64 [[TMP2]], ptr [[TMP3]], align 8
291*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP4:%.*]] = add i32 [[GP_OFFSET]], 8
292*a27f40e5SLongsheng Mou // CHECK-NEXT:    store i32 [[TMP4]], ptr [[GP_OFFSET_P]], align 16
293*a27f40e5SLongsheng Mou // CHECK-NEXT:    br label [[VAARG_END:%.*]]
294*a27f40e5SLongsheng Mou // CHECK:       vaarg.in_mem:
295*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[OVERFLOW_ARG_AREA_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 2
296*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[OVERFLOW_ARG_AREA:%.*]] = load ptr, ptr [[OVERFLOW_ARG_AREA_P]], align 8
297*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[OVERFLOW_ARG_AREA_NEXT:%.*]] = getelementptr i8, ptr [[OVERFLOW_ARG_AREA]], i32 16
298*a27f40e5SLongsheng Mou // CHECK-NEXT:    store ptr [[OVERFLOW_ARG_AREA_NEXT]], ptr [[OVERFLOW_ARG_AREA_P]], align 8
299*a27f40e5SLongsheng Mou // CHECK-NEXT:    br label [[VAARG_END]]
300*a27f40e5SLongsheng Mou // CHECK:       vaarg.end:
301*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[VAARG_ADDR:%.*]] = phi ptr [ [[TMP]], [[VAARG_IN_REG]] ], [ [[OVERFLOW_ARG_AREA]], [[VAARG_IN_MEM]] ]
302*a27f40e5SLongsheng Mou // CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL]], ptr align 8 [[VAARG_ADDR]], i64 16, i1 false)
303*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_S6]], ptr [[RETVAL]], i32 0, i32 0
304*a27f40e5SLongsheng Mou // CHECK-NEXT:    [[TMP5:%.*]] = load i64, ptr [[COERCE_DIVE]], align 8
305*a27f40e5SLongsheng Mou // CHECK-NEXT:    ret i64 [[TMP5]]
306*a27f40e5SLongsheng Mou //
307*a27f40e5SLongsheng Mou s6 f6(int z, ...) {
308*a27f40e5SLongsheng Mou   __builtin_va_list list;
309*a27f40e5SLongsheng Mou   __builtin_va_start(list, z);
310*a27f40e5SLongsheng Mou   return __builtin_va_arg(list, s6);
311*a27f40e5SLongsheng Mou }
312