xref: /llvm-project/llvm/test/CodeGen/NVPTX/variadics-lowering.ll (revision 38fffa630ee80163dc65e759392ad29798905679)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2; RUN: opt -S -mtriple=nvptx64-- --passes=expand-variadics --expand-variadics-override=lowering < %s | FileCheck %s
3
4%struct.S1 = type { i32, i8, i64 }
5%struct.S2 = type { i64, i64 }
6
7@__const.bar.s1 = private unnamed_addr constant %struct.S1 { i32 1, i8 1, i64 1 }, align 8
8@__const.qux.s = private unnamed_addr constant %struct.S2 { i64 1, i64 1 }, align 8
9
10define dso_local i32 @variadics1(i32 noundef %first, ...) {
11; CHECK-LABEL: define dso_local i32 @variadics1(
12; CHECK-SAME: i32 noundef [[FIRST:%.*]], ptr [[VARARGS:%.*]]) {
13; CHECK-NEXT:  [[ENTRY:.*:]]
14; CHECK-NEXT:    [[VLIST:%.*]] = alloca ptr, align 8
15; CHECK-NEXT:    store ptr [[VARARGS]], ptr [[VLIST]], align 8
16; CHECK-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[VLIST]], align 8
17; CHECK-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i64 4
18; CHECK-NEXT:    store ptr [[ARGP_NEXT]], ptr [[VLIST]], align 8
19; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[ARGP_CUR]], align 4
20; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[FIRST]], [[TMP0]]
21; CHECK-NEXT:    [[ARGP_CUR1:%.*]] = load ptr, ptr [[VLIST]], align 8
22; CHECK-NEXT:    [[ARGP_NEXT2:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR1]], i64 4
23; CHECK-NEXT:    store ptr [[ARGP_NEXT2]], ptr [[VLIST]], align 8
24; CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[ARGP_CUR1]], align 4
25; CHECK-NEXT:    [[ADD3:%.*]] = add nsw i32 [[ADD]], [[TMP1]]
26; CHECK-NEXT:    [[ARGP_CUR4:%.*]] = load ptr, ptr [[VLIST]], align 8
27; CHECK-NEXT:    [[ARGP_NEXT5:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR4]], i64 4
28; CHECK-NEXT:    store ptr [[ARGP_NEXT5]], ptr [[VLIST]], align 8
29; CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[ARGP_CUR4]], align 4
30; CHECK-NEXT:    [[ADD6:%.*]] = add nsw i32 [[ADD3]], [[TMP2]]
31; CHECK-NEXT:    [[ARGP_CUR7:%.*]] = load ptr, ptr [[VLIST]], align 8
32; CHECK-NEXT:    [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR7]], i32 7
33; CHECK-NEXT:    [[ARGP_CUR7_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[TMP3]], i64 -8)
34; CHECK-NEXT:    [[ARGP_NEXT8:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR7_ALIGNED]], i64 8
35; CHECK-NEXT:    store ptr [[ARGP_NEXT8]], ptr [[VLIST]], align 8
36; CHECK-NEXT:    [[TMP4:%.*]] = load i64, ptr [[ARGP_CUR7_ALIGNED]], align 8
37; CHECK-NEXT:    [[CONV:%.*]] = sext i32 [[ADD6]] to i64
38; CHECK-NEXT:    [[ADD9:%.*]] = add nsw i64 [[CONV]], [[TMP4]]
39; CHECK-NEXT:    [[CONV10:%.*]] = trunc i64 [[ADD9]] to i32
40; CHECK-NEXT:    [[ARGP_CUR11:%.*]] = load ptr, ptr [[VLIST]], align 8
41; CHECK-NEXT:    [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR11]], i32 7
42; CHECK-NEXT:    [[ARGP_CUR11_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[TMP5]], i64 -8)
43; CHECK-NEXT:    [[ARGP_NEXT12:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR11_ALIGNED]], i64 8
44; CHECK-NEXT:    store ptr [[ARGP_NEXT12]], ptr [[VLIST]], align 8
45; CHECK-NEXT:    [[TMP6:%.*]] = load double, ptr [[ARGP_CUR11_ALIGNED]], align 8
46; CHECK-NEXT:    [[CONV13:%.*]] = sitofp i32 [[CONV10]] to double
47; CHECK-NEXT:    [[ADD14:%.*]] = fadd double [[CONV13]], [[TMP6]]
48; CHECK-NEXT:    [[CONV15:%.*]] = fptosi double [[ADD14]] to i32
49; CHECK-NEXT:    [[ARGP_CUR16:%.*]] = load ptr, ptr [[VLIST]], align 8
50; CHECK-NEXT:    [[TMP7:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR16]], i32 7
51; CHECK-NEXT:    [[ARGP_CUR16_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[TMP7]], i64 -8)
52; CHECK-NEXT:    [[ARGP_NEXT17:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR16_ALIGNED]], i64 8
53; CHECK-NEXT:    store ptr [[ARGP_NEXT17]], ptr [[VLIST]], align 8
54; CHECK-NEXT:    [[TMP8:%.*]] = load double, ptr [[ARGP_CUR16_ALIGNED]], align 8
55; CHECK-NEXT:    [[CONV18:%.*]] = sitofp i32 [[CONV15]] to double
56; CHECK-NEXT:    [[ADD19:%.*]] = fadd double [[CONV18]], [[TMP8]]
57; CHECK-NEXT:    [[CONV20:%.*]] = fptosi double [[ADD19]] to i32
58; CHECK-NEXT:    ret i32 [[CONV20]]
59;
60entry:
61  %vlist = alloca ptr, align 8
62  call void @llvm.va_start.p0(ptr %vlist)
63  %argp.cur = load ptr, ptr %vlist, align 8
64  %argp.next = getelementptr inbounds i8, ptr %argp.cur, i64 4
65  store ptr %argp.next, ptr %vlist, align 8
66  %0 = load i32, ptr %argp.cur, align 4
67  %add = add nsw i32 %first, %0
68  %argp.cur1 = load ptr, ptr %vlist, align 8
69  %argp.next2 = getelementptr inbounds i8, ptr %argp.cur1, i64 4
70  store ptr %argp.next2, ptr %vlist, align 8
71  %1 = load i32, ptr %argp.cur1, align 4
72  %add3 = add nsw i32 %add, %1
73  %argp.cur4 = load ptr, ptr %vlist, align 8
74  %argp.next5 = getelementptr inbounds i8, ptr %argp.cur4, i64 4
75  store ptr %argp.next5, ptr %vlist, align 8
76  %2 = load i32, ptr %argp.cur4, align 4
77  %add6 = add nsw i32 %add3, %2
78  %argp.cur7 = load ptr, ptr %vlist, align 8
79  %3 = getelementptr inbounds i8, ptr %argp.cur7, i32 7
80  %argp.cur7.aligned = call ptr @llvm.ptrmask.p0.i64(ptr %3, i64 -8)
81  %argp.next8 = getelementptr inbounds i8, ptr %argp.cur7.aligned, i64 8
82  store ptr %argp.next8, ptr %vlist, align 8
83  %4 = load i64, ptr %argp.cur7.aligned, align 8
84  %conv = sext i32 %add6 to i64
85  %add9 = add nsw i64 %conv, %4
86  %conv10 = trunc i64 %add9 to i32
87  %argp.cur11 = load ptr, ptr %vlist, align 8
88  %5 = getelementptr inbounds i8, ptr %argp.cur11, i32 7
89  %argp.cur11.aligned = call ptr @llvm.ptrmask.p0.i64(ptr %5, i64 -8)
90  %argp.next12 = getelementptr inbounds i8, ptr %argp.cur11.aligned, i64 8
91  store ptr %argp.next12, ptr %vlist, align 8
92  %6 = load double, ptr %argp.cur11.aligned, align 8
93  %conv13 = sitofp i32 %conv10 to double
94  %add14 = fadd double %conv13, %6
95  %conv15 = fptosi double %add14 to i32
96  %argp.cur16 = load ptr, ptr %vlist, align 8
97  %7 = getelementptr inbounds i8, ptr %argp.cur16, i32 7
98  %argp.cur16.aligned = call ptr @llvm.ptrmask.p0.i64(ptr %7, i64 -8)
99  %argp.next17 = getelementptr inbounds i8, ptr %argp.cur16.aligned, i64 8
100  store ptr %argp.next17, ptr %vlist, align 8
101  %8 = load double, ptr %argp.cur16.aligned, align 8
102  %conv18 = sitofp i32 %conv15 to double
103  %add19 = fadd double %conv18, %8
104  %conv20 = fptosi double %add19 to i32
105  call void @llvm.va_end.p0(ptr %vlist)
106  ret i32 %conv20
107}
108
109declare void @llvm.va_start.p0(ptr)
110
111declare ptr @llvm.ptrmask.p0.i64(ptr, i64)
112
113declare void @llvm.va_end.p0(ptr)
114
115define dso_local i32 @foo() {
116; CHECK-LABEL: define dso_local i32 @foo() {
117; CHECK-NEXT:  [[ENTRY:.*:]]
118; CHECK-NEXT:    [[VARARG_BUFFER:%.*]] = alloca [[FOO_VARARG:%.*]], align 8
119; CHECK-NEXT:    [[CONV:%.*]] = sext i8 1 to i32
120; CHECK-NEXT:    [[CONV1:%.*]] = sext i16 1 to i32
121; CHECK-NEXT:    [[CONV2:%.*]] = fpext float 1.000000e+00 to double
122; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 40, ptr [[VARARG_BUFFER]])
123; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw [[FOO_VARARG]], ptr [[VARARG_BUFFER]], i32 0, i32 0
124; CHECK-NEXT:    store i32 [[CONV]], ptr [[TMP0]], align 4
125; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw [[FOO_VARARG]], ptr [[VARARG_BUFFER]], i32 0, i32 1
126; CHECK-NEXT:    store i32 [[CONV1]], ptr [[TMP1]], align 4
127; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds nuw [[FOO_VARARG]], ptr [[VARARG_BUFFER]], i32 0, i32 2
128; CHECK-NEXT:    store i32 1, ptr [[TMP2]], align 4
129; CHECK-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw [[FOO_VARARG]], ptr [[VARARG_BUFFER]], i32 0, i32 4
130; CHECK-NEXT:    store i64 1, ptr [[TMP3]], align 8
131; CHECK-NEXT:    [[TMP4:%.*]] = getelementptr inbounds nuw [[FOO_VARARG]], ptr [[VARARG_BUFFER]], i32 0, i32 5
132; CHECK-NEXT:    store double [[CONV2]], ptr [[TMP4]], align 8
133; CHECK-NEXT:    [[TMP5:%.*]] = getelementptr inbounds nuw [[FOO_VARARG]], ptr [[VARARG_BUFFER]], i32 0, i32 6
134; CHECK-NEXT:    store double 1.000000e+00, ptr [[TMP5]], align 8
135; CHECK-NEXT:    [[CALL:%.*]] = call i32 @variadics1(i32 noundef 1, ptr [[VARARG_BUFFER]])
136; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 40, ptr [[VARARG_BUFFER]])
137; CHECK-NEXT:    ret i32 [[CALL]]
138;
139entry:
140  %conv = sext i8 1 to i32
141  %conv1 = sext i16 1 to i32
142  %conv2 = fpext float 1.000000e+00 to double
143  %call = call i32 (i32, ...) @variadics1(i32 noundef 1, i32 noundef %conv, i32 noundef %conv1, i32 noundef 1, i64 noundef 1, double noundef %conv2, double noundef 1.000000e+00)
144  ret i32 %call
145}
146
147define dso_local i32 @variadics2(i32 noundef %first, ...) {
148; CHECK-LABEL: define dso_local i32 @variadics2(
149; CHECK-SAME: i32 noundef [[FIRST:%.*]], ptr [[VARARGS:%.*]]) {
150; CHECK-NEXT:  [[ENTRY:.*:]]
151; CHECK-NEXT:    [[VLIST:%.*]] = alloca ptr, align 8
152; CHECK-NEXT:    [[S1_SROA_3:%.*]] = alloca [3 x i8], align 1
153; CHECK-NEXT:    store ptr [[VARARGS]], ptr [[VLIST]], align 8
154; CHECK-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[VLIST]], align 8
155; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 7
156; CHECK-NEXT:    [[ARGP_CUR_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[TMP0]], i64 -8)
157; CHECK-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR_ALIGNED]], i64 16
158; CHECK-NEXT:    store ptr [[ARGP_NEXT]], ptr [[VLIST]], align 8
159; CHECK-NEXT:    [[S1_SROA_0_0_COPYLOAD:%.*]] = load i32, ptr [[ARGP_CUR_ALIGNED]], align 8
160; CHECK-NEXT:    [[S1_SROA_2_0_ARGP_CUR_ALIGNED_SROA_IDX:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR_ALIGNED]], i64 4
161; CHECK-NEXT:    [[S1_SROA_2_0_COPYLOAD:%.*]] = load i8, ptr [[S1_SROA_2_0_ARGP_CUR_ALIGNED_SROA_IDX]], align 4
162; CHECK-NEXT:    [[S1_SROA_3_0_ARGP_CUR_ALIGNED_SROA_IDX:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR_ALIGNED]], i64 5
163; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[S1_SROA_3]], ptr align 1 [[S1_SROA_3_0_ARGP_CUR_ALIGNED_SROA_IDX]], i64 3, i1 false)
164; CHECK-NEXT:    [[S1_SROA_31_0_ARGP_CUR_ALIGNED_SROA_IDX:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR_ALIGNED]], i64 8
165; CHECK-NEXT:    [[S1_SROA_31_0_COPYLOAD:%.*]] = load i64, ptr [[S1_SROA_31_0_ARGP_CUR_ALIGNED_SROA_IDX]], align 8
166; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[FIRST]], [[S1_SROA_0_0_COPYLOAD]]
167; CHECK-NEXT:    [[CONV:%.*]] = sext i8 [[S1_SROA_2_0_COPYLOAD]] to i32
168; CHECK-NEXT:    [[ADD1:%.*]] = add nsw i32 [[ADD]], [[CONV]]
169; CHECK-NEXT:    [[CONV2:%.*]] = sext i32 [[ADD1]] to i64
170; CHECK-NEXT:    [[ADD3:%.*]] = add nsw i64 [[CONV2]], [[S1_SROA_31_0_COPYLOAD]]
171; CHECK-NEXT:    [[CONV4:%.*]] = trunc i64 [[ADD3]] to i32
172; CHECK-NEXT:    ret i32 [[CONV4]]
173;
174entry:
175  %vlist = alloca ptr, align 8
176  %s1.sroa.3 = alloca [3 x i8], align 1
177  call void @llvm.va_start.p0(ptr %vlist)
178  %argp.cur = load ptr, ptr %vlist, align 8
179  %0 = getelementptr inbounds i8, ptr %argp.cur, i32 7
180  %argp.cur.aligned = call ptr @llvm.ptrmask.p0.i64(ptr %0, i64 -8)
181  %argp.next = getelementptr inbounds i8, ptr %argp.cur.aligned, i64 16
182  store ptr %argp.next, ptr %vlist, align 8
183  %s1.sroa.0.0.copyload = load i32, ptr %argp.cur.aligned, align 8
184  %s1.sroa.2.0.argp.cur.aligned.sroa_idx = getelementptr inbounds i8, ptr %argp.cur.aligned, i64 4
185  %s1.sroa.2.0.copyload = load i8, ptr %s1.sroa.2.0.argp.cur.aligned.sroa_idx, align 4
186  %s1.sroa.3.0.argp.cur.aligned.sroa_idx = getelementptr inbounds i8, ptr %argp.cur.aligned, i64 5
187  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %s1.sroa.3, ptr align 1 %s1.sroa.3.0.argp.cur.aligned.sroa_idx, i64 3, i1 false)
188  %s1.sroa.31.0.argp.cur.aligned.sroa_idx = getelementptr inbounds i8, ptr %argp.cur.aligned, i64 8
189  %s1.sroa.31.0.copyload = load i64, ptr %s1.sroa.31.0.argp.cur.aligned.sroa_idx, align 8
190  %add = add nsw i32 %first, %s1.sroa.0.0.copyload
191  %conv = sext i8 %s1.sroa.2.0.copyload to i32
192  %add1 = add nsw i32 %add, %conv
193  %conv2 = sext i32 %add1 to i64
194  %add3 = add nsw i64 %conv2, %s1.sroa.31.0.copyload
195  %conv4 = trunc i64 %add3 to i32
196  call void @llvm.va_end.p0(ptr %vlist)
197  ret i32 %conv4
198}
199
200declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg)
201
202define dso_local i32 @bar() {
203; CHECK-LABEL: define dso_local i32 @bar() {
204; CHECK-NEXT:  [[ENTRY:.*:]]
205; CHECK-NEXT:    [[S1_SROA_3:%.*]] = alloca [3 x i8], align 1
206; CHECK-NEXT:    [[VARARG_BUFFER:%.*]] = alloca [[BAR_VARARG:%.*]], align 8
207; CHECK-NEXT:    [[S1_SROA_0_0_COPYLOAD:%.*]] = load i32, ptr @__const.bar.s1, align 8
208; CHECK-NEXT:    [[S1_SROA_2_0_COPYLOAD:%.*]] = load i8, ptr getelementptr inbounds (i8, ptr @__const.bar.s1, i64 4), align 4
209; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[S1_SROA_3]], ptr align 1 getelementptr inbounds (i8, ptr @__const.bar.s1, i64 5), i64 3, i1 false)
210; CHECK-NEXT:    [[S1_SROA_31_0_COPYLOAD:%.*]] = load i64, ptr getelementptr inbounds (i8, ptr @__const.bar.s1, i64 8), align 8
211; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 16, ptr [[VARARG_BUFFER]])
212; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw [[BAR_VARARG]], ptr [[VARARG_BUFFER]], i32 0, i32 0
213; CHECK-NEXT:    store i32 [[S1_SROA_0_0_COPYLOAD]], ptr [[TMP0]], align 4
214; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw [[BAR_VARARG]], ptr [[VARARG_BUFFER]], i32 0, i32 1
215; CHECK-NEXT:    store i8 [[S1_SROA_2_0_COPYLOAD]], ptr [[TMP1]], align 1
216; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds nuw [[BAR_VARARG]], ptr [[VARARG_BUFFER]], i32 0, i32 3
217; CHECK-NEXT:    store i64 [[S1_SROA_31_0_COPYLOAD]], ptr [[TMP2]], align 8
218; CHECK-NEXT:    [[CALL:%.*]] = call i32 @variadics2(i32 noundef 1, ptr [[VARARG_BUFFER]])
219; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 16, ptr [[VARARG_BUFFER]])
220; CHECK-NEXT:    ret i32 [[CALL]]
221;
222entry:
223  %s1.sroa.3 = alloca [3 x i8], align 1
224  %s1.sroa.0.0.copyload = load i32, ptr @__const.bar.s1, align 8
225  %s1.sroa.2.0.copyload = load i8, ptr getelementptr inbounds (i8, ptr @__const.bar.s1, i64 4), align 4
226  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %s1.sroa.3, ptr align 1 getelementptr inbounds (i8, ptr @__const.bar.s1, i64 5), i64 3, i1 false)
227  %s1.sroa.31.0.copyload = load i64, ptr getelementptr inbounds (i8, ptr @__const.bar.s1, i64 8), align 8
228  %call = call i32 (i32, ...) @variadics2(i32 noundef 1, i32 %s1.sroa.0.0.copyload, i8 %s1.sroa.2.0.copyload, i64 %s1.sroa.31.0.copyload)
229  ret i32 %call
230}
231
232define dso_local i32 @variadics3(i32 noundef %first, ...) {
233; CHECK-LABEL: define dso_local i32 @variadics3(
234; CHECK-SAME: i32 noundef [[FIRST:%.*]], ptr [[VARARGS:%.*]]) {
235; CHECK-NEXT:  [[ENTRY:.*:]]
236; CHECK-NEXT:    [[VLIST:%.*]] = alloca ptr, align 8
237; CHECK-NEXT:    store ptr [[VARARGS]], ptr [[VLIST]], align 8
238; CHECK-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[VLIST]], align 8
239; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 15
240; CHECK-NEXT:    [[ARGP_CUR_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[TMP0]], i64 -16)
241; CHECK-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR_ALIGNED]], i64 16
242; CHECK-NEXT:    store ptr [[ARGP_NEXT]], ptr [[VLIST]], align 8
243; CHECK-NEXT:    [[TMP1:%.*]] = load <4 x i32>, ptr [[ARGP_CUR_ALIGNED]], align 16
244; CHECK-NEXT:    [[TMP2:%.*]] = extractelement <4 x i32> [[TMP1]], i64 0
245; CHECK-NEXT:    [[TMP3:%.*]] = extractelement <4 x i32> [[TMP1]], i64 1
246; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[TMP2]], [[TMP3]]
247; CHECK-NEXT:    [[TMP4:%.*]] = extractelement <4 x i32> [[TMP1]], i64 2
248; CHECK-NEXT:    [[ADD1:%.*]] = add nsw i32 [[ADD]], [[TMP4]]
249; CHECK-NEXT:    [[TMP5:%.*]] = extractelement <4 x i32> [[TMP1]], i64 3
250; CHECK-NEXT:    [[ADD2:%.*]] = add nsw i32 [[ADD1]], [[TMP5]]
251; CHECK-NEXT:    ret i32 [[ADD2]]
252;
253entry:
254  %vlist = alloca ptr, align 8
255  call void @llvm.va_start.p0(ptr %vlist)
256  %argp.cur = load ptr, ptr %vlist, align 8
257  %0 = getelementptr inbounds i8, ptr %argp.cur, i32 15
258  %argp.cur.aligned = call ptr @llvm.ptrmask.p0.i64(ptr %0, i64 -16)
259  %argp.next = getelementptr inbounds i8, ptr %argp.cur.aligned, i64 16
260  store ptr %argp.next, ptr %vlist, align 8
261  %1 = load <4 x i32>, ptr %argp.cur.aligned, align 16
262  call void @llvm.va_end.p0(ptr %vlist)
263  %2 = extractelement <4 x i32> %1, i64 0
264  %3 = extractelement <4 x i32> %1, i64 1
265  %add = add nsw i32 %2, %3
266  %4 = extractelement <4 x i32> %1, i64 2
267  %add1 = add nsw i32 %add, %4
268  %5 = extractelement <4 x i32> %1, i64 3
269  %add2 = add nsw i32 %add1, %5
270  ret i32 %add2
271}
272
273define dso_local i32 @baz() {
274; CHECK-LABEL: define dso_local i32 @baz() {
275; CHECK-NEXT:  [[ENTRY:.*:]]
276; CHECK-NEXT:    [[VARARG_BUFFER:%.*]] = alloca [[BAZ_VARARG:%.*]], align 16
277; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 16, ptr [[VARARG_BUFFER]])
278; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw [[BAZ_VARARG]], ptr [[VARARG_BUFFER]], i32 0, i32 0
279; CHECK-NEXT:    store <4 x i32> splat (i32 1), ptr [[TMP0]], align 16
280; CHECK-NEXT:    [[CALL:%.*]] = call i32 @variadics3(i32 noundef 1, ptr [[VARARG_BUFFER]])
281; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 16, ptr [[VARARG_BUFFER]])
282; CHECK-NEXT:    ret i32 [[CALL]]
283;
284entry:
285  %call = call i32 (i32, ...) @variadics3(i32 noundef 1, <4 x i32> noundef <i32 1, i32 1, i32 1, i32 1>)
286  ret i32 %call
287}
288
289define dso_local i32 @variadics4(ptr noundef byval(%struct.S2) align 8 %first, ...) {
290; CHECK-LABEL: define dso_local i32 @variadics4(
291; CHECK-SAME: ptr noundef byval([[STRUCT_S2:%.*]]) align 8 [[FIRST:%.*]], ptr [[VARARGS:%.*]]) {
292; CHECK-NEXT:  [[ENTRY:.*:]]
293; CHECK-NEXT:    [[VLIST:%.*]] = alloca ptr, align 8
294; CHECK-NEXT:    store ptr [[VARARGS]], ptr [[VLIST]], align 8
295; CHECK-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[VLIST]], align 8
296; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 7
297; CHECK-NEXT:    [[ARGP_CUR_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[TMP0]], i64 -8)
298; CHECK-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR_ALIGNED]], i64 8
299; CHECK-NEXT:    store ptr [[ARGP_NEXT]], ptr [[VLIST]], align 8
300; CHECK-NEXT:    [[TMP1:%.*]] = load i64, ptr [[ARGP_CUR_ALIGNED]], align 8
301; CHECK-NEXT:    [[X1:%.*]] = getelementptr inbounds [[STRUCT_S2]], ptr [[FIRST]], i32 0, i32 0
302; CHECK-NEXT:    [[TMP2:%.*]] = load i64, ptr [[X1]], align 8
303; CHECK-NEXT:    [[Y:%.*]] = getelementptr inbounds [[STRUCT_S2]], ptr [[FIRST]], i32 0, i32 1
304; CHECK-NEXT:    [[TMP3:%.*]] = load i64, ptr [[Y]], align 8
305; CHECK-NEXT:    [[ADD:%.*]] = add nsw i64 [[TMP2]], [[TMP3]]
306; CHECK-NEXT:    [[ADD2:%.*]] = add nsw i64 [[ADD]], [[TMP1]]
307; CHECK-NEXT:    [[CONV:%.*]] = trunc i64 [[ADD2]] to i32
308; CHECK-NEXT:    ret i32 [[CONV]]
309;
310entry:
311  %vlist = alloca ptr, align 8
312  call void @llvm.va_start.p0(ptr %vlist)
313  %argp.cur = load ptr, ptr %vlist, align 8
314  %0 = getelementptr inbounds i8, ptr %argp.cur, i32 7
315  %argp.cur.aligned = call ptr @llvm.ptrmask.p0.i64(ptr %0, i64 -8)
316  %argp.next = getelementptr inbounds i8, ptr %argp.cur.aligned, i64 8
317  store ptr %argp.next, ptr %vlist, align 8
318  %1 = load i64, ptr %argp.cur.aligned, align 8
319  %x1 = getelementptr inbounds %struct.S2, ptr %first, i32 0, i32 0
320  %2 = load i64, ptr %x1, align 8
321  %y = getelementptr inbounds %struct.S2, ptr %first, i32 0, i32 1
322  %3 = load i64, ptr %y, align 8
323  %add = add nsw i64 %2, %3
324  %add2 = add nsw i64 %add, %1
325  %conv = trunc i64 %add2 to i32
326  call void @llvm.va_end.p0(ptr %vlist)
327  ret i32 %conv
328}
329
330define dso_local void @qux() {
331; CHECK-LABEL: define dso_local void @qux() {
332; CHECK-NEXT:  [[ENTRY:.*:]]
333; CHECK-NEXT:    [[S:%.*]] = alloca [[STRUCT_S2:%.*]], align 8
334; CHECK-NEXT:    [[VARARG_BUFFER:%.*]] = alloca [[QUX_VARARG:%.*]], align 8
335; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[S]], ptr align 8 @__const.qux.s, i64 16, i1 false)
336; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 8, ptr [[VARARG_BUFFER]])
337; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw [[QUX_VARARG]], ptr [[VARARG_BUFFER]], i32 0, i32 0
338; CHECK-NEXT:    store i64 1, ptr [[TMP0]], align 8
339; CHECK-NEXT:    [[CALL:%.*]] = call i32 @variadics4(ptr noundef byval([[STRUCT_S2]]) align 8 [[S]], ptr [[VARARG_BUFFER]])
340; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 8, ptr [[VARARG_BUFFER]])
341; CHECK-NEXT:    ret void
342;
343entry:
344  %s = alloca %struct.S2, align 8
345  call void @llvm.memcpy.p0.p0.i64(ptr align 8 %s, ptr align 8 @__const.qux.s, i64 16, i1 false)
346  %call = call i32 (ptr, ...) @variadics4(ptr noundef byval(%struct.S2) align 8 %s, i64 noundef 1)
347  ret void
348}
349