1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: -p --function-signature
2 ; RUN: opt -mtriple=wasm32-unknown-unknown -S --passes=expand-variadics --expand-variadics-override=optimize < %s | FileCheck %s --check-prefixes=OPT
3 ; RUN: opt -mtriple=wasm32-unknown-unknown -S --passes=expand-variadics --expand-variadics-override=lowering < %s | FileCheck %s --check-prefixes=ABI
4 ; REQUIRES: webassembly-registered-target
6 ; Examples are variadic functions that return the first or the second of an int and a double
7 ; Split the functions into an internal equivalent that takes a va_list and a ABI preserving wrapper
9 define i32 @variadic_int_double_get_firstz(...) {
10 ; OPT-LABEL: define {{[^@]+}}@variadic_int_double_get_firstz(...) {
12 ; OPT-NEXT: %va_start = alloca ptr, align 4
13 ; OPT-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr %va_start)
14 ; OPT-NEXT: call void @llvm.va_start.p0(ptr %va_start)
15 ; OPT-NEXT: %0 = load ptr, ptr %va_start, align 4
16 ; OPT-NEXT: %1 = call i32 @variadic_int_double_get_firstz.valist(ptr %0)
17 ; OPT-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr %va_start)
18 ; OPT-NEXT: ret i32 %1
20 ; ABI-LABEL: define {{[^@]+}}@variadic_int_double_get_firstz(ptr %varargs) {
22 ; ABI-NEXT: %va = alloca ptr, align 4
23 ; ABI-NEXT: store ptr %varargs, ptr %va, align 4
24 ; ABI-NEXT: %argp.cur = load ptr, ptr %va, align 4
25 ; ABI-NEXT: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4
26 ; ABI-NEXT: store ptr %argp.next, ptr %va, align 4
27 ; ABI-NEXT: %0 = load i32, ptr %argp.cur, align 4
28 ; ABI-NEXT: ret i32 %0
31 %va = alloca ptr, align 4
32 call void @llvm.va_start.p0(ptr nonnull %va)
33 %argp.cur = load ptr, ptr %va, align 4
34 %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4
35 store ptr %argp.next, ptr %va, align 4
36 %0 = load i32, ptr %argp.cur, align 4
37 call void @llvm.va_end.p0(ptr %va)
41 ; CHECK-LABEL: define i32 @variadic_int_double_get_firstz(...) {
43 ; CHECK-NEXT: %va_list = alloca ptr, align 4
44 ; CHECK-NEXT: call void @llvm.va_start.p0(ptr %va_list)
45 ; CHECK-NEXT: %0 = tail call i32 @variadic_int_double_get_firstz.valist(ptr %va_list)
46 ; CHECK-NEXT: ret i32 %0
49 ; CHECK-LABEL: define internal i32 @variadic_int_double_get_firstz.valist(ptr noalias %varargs) {
51 ; CHECK-NEXT: %va = alloca ptr, align 4
52 ; CHECK-NEXT: store ptr %varargs, ptr %va, align 4
53 ; CHECK-NEXT: %argp.cur = load ptr, ptr %va, align 4
54 ; CHECK-NEXT: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4
55 ; CHECK-NEXT: store ptr %argp.next, ptr %va, align 4
56 ; CHECK-NEXT: %0 = load i32, ptr %argp.cur, align 4
57 ; CHECK-NEXT: ret i32 %0
60 define double @variadic_int_double_get_secondz(...) {
61 ; OPT-LABEL: define {{[^@]+}}@variadic_int_double_get_secondz(...) {
63 ; OPT-NEXT: %va_start = alloca ptr, align 4
64 ; OPT-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr %va_start)
65 ; OPT-NEXT: call void @llvm.va_start.p0(ptr %va_start)
66 ; OPT-NEXT: %0 = load ptr, ptr %va_start, align 4
67 ; OPT-NEXT: %1 = call double @variadic_int_double_get_secondz.valist(ptr %0)
68 ; OPT-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr %va_start)
69 ; OPT-NEXT: ret double %1
71 ; ABI-LABEL: define {{[^@]+}}@variadic_int_double_get_secondz(ptr %varargs) {
73 ; ABI-NEXT: %va = alloca ptr, align 4
74 ; ABI-NEXT: store ptr %varargs, ptr %va, align 4
75 ; ABI-NEXT: %argp.cur = load ptr, ptr %va, align 4
76 ; ABI-NEXT: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4
77 ; ABI-NEXT: %argp.next2 = getelementptr inbounds i8, ptr %argp.cur, i32 12
78 ; ABI-NEXT: store ptr %argp.next2, ptr %va, align 4
79 ; ABI-NEXT: %0 = load double, ptr %argp.next, align 4
80 ; ABI-NEXT: ret double %0
83 %va = alloca ptr, align 4
84 call void @llvm.va_start.p0(ptr nonnull %va)
85 %argp.cur = load ptr, ptr %va, align 4
86 %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4
87 %argp.next2 = getelementptr inbounds i8, ptr %argp.cur, i32 12
88 store ptr %argp.next2, ptr %va, align 4
89 %0 = load double, ptr %argp.next, align 4
90 call void @llvm.va_end.p0(ptr %va)
94 ; CHECK-LABEL: define double @variadic_int_double_get_secondz(...) {
96 ; CHECK-NEXT: %va_list = alloca ptr, align 4
97 ; CHECK-NEXT: call void @llvm.va_start.p0(ptr %va_list)
98 ; CHECK-NEXT: %0 = tail call double @variadic_int_double_get_secondz.valist(ptr %va_list)
99 ; CHECK-NEXT: ret double %0
102 ; CHECK-LABEL: define internal double @variadic_int_double_get_secondz.valist(ptr noalias %varargs) {
104 ; CHECK-NEXT: %va = alloca ptr, align 4
105 ; CHECK-NEXT: store ptr %varargs, ptr %va, align 4
106 ; CHECK-NEXT: %argp.cur = load ptr, ptr %va, align 4
107 ; CHECK-NEXT: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4
108 ; CHECK-NEXT: %argp.next2 = getelementptr inbounds i8, ptr %argp.cur, i32 12
109 ; CHECK-NEXT: store ptr %argp.next2, ptr %va, align 4
110 ; CHECK-NEXT: %0 = load double, ptr %argp.next, align 4
111 ; CHECK-NEXT: ret double %0
115 ; CHECK-LABEL: @variadic_can_get_firstIidEEbT_T0_(i32 %x, double %y) {
117 ; CHECK-NEXT: %vararg_buffer = alloca %variadic_can_get_firstIidEEbT_T0_.vararg, align 16
118 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr %vararg_buffer)
119 ; CHECK-NEXT: %0 = getelementptr inbounds %variadic_can_get_firstIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 0
120 ; CHECK-NEXT: store i32 %x, ptr %0, align 4
121 ; CHECK-NEXT: %1 = getelementptr inbounds %variadic_can_get_firstIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 1
122 ; CHECK-NEXT: store double %y, ptr %1, align 4
123 ; CHECK-NEXT: %call = call i32 @variadic_int_double_get_firstz.valist(ptr %vararg_buffer)
124 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr %vararg_buffer)
125 ; CHECK-NEXT: %cmp.i = icmp eq i32 %call, %x
126 ; CHECK-NEXT: ret i1 %cmp.i
129 define zeroext i1 @variadic_can_get_firstIidEEbT_T0_(i32 %x, double %y) {
130 ; OPT-LABEL: define {{[^@]+}}@variadic_can_get_firstIidEEbT_T0_(i32 %x, double %y) {
132 ; OPT-NEXT: %vararg_buffer = alloca %variadic_can_get_firstIidEEbT_T0_.vararg, align 16
133 ; OPT-NEXT: call void @llvm.lifetime.start.p0(i64 16, ptr %vararg_buffer)
134 ; OPT-NEXT: %0 = getelementptr inbounds nuw %variadic_can_get_firstIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 0
135 ; OPT-NEXT: store i32 %x, ptr %0, align 4
136 ; OPT-NEXT: %1 = getelementptr inbounds nuw %variadic_can_get_firstIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 2
137 ; OPT-NEXT: store double %y, ptr %1, align 8
138 ; OPT-NEXT: %call = call i32 @variadic_int_double_get_firstz.valist(ptr %vararg_buffer)
139 ; OPT-NEXT: call void @llvm.lifetime.end.p0(i64 16, ptr %vararg_buffer)
140 ; OPT-NEXT: %cmp.i = icmp eq i32 %call, %x
141 ; OPT-NEXT: ret i1 %cmp.i
143 ; ABI-LABEL: define {{[^@]+}}@variadic_can_get_firstIidEEbT_T0_(i32 %x, double %y) {
145 ; ABI-NEXT: %vararg_buffer = alloca %variadic_can_get_firstIidEEbT_T0_.vararg, align 16
146 ; ABI-NEXT: call void @llvm.lifetime.start.p0(i64 16, ptr %vararg_buffer)
147 ; ABI-NEXT: %0 = getelementptr inbounds nuw %variadic_can_get_firstIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 0
148 ; ABI-NEXT: store i32 %x, ptr %0, align 4
149 ; ABI-NEXT: %1 = getelementptr inbounds nuw %variadic_can_get_firstIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 2
150 ; ABI-NEXT: store double %y, ptr %1, align 8
151 ; ABI-NEXT: %call = call i32 @variadic_int_double_get_firstz(ptr %vararg_buffer)
152 ; ABI-NEXT: call void @llvm.lifetime.end.p0(i64 16, ptr %vararg_buffer)
153 ; ABI-NEXT: %cmp.i = icmp eq i32 %call, %x
154 ; ABI-NEXT: ret i1 %cmp.i
157 %call = call i32 (...) @variadic_int_double_get_firstz(i32 %x, double %y)
158 %cmp.i = icmp eq i32 %call, %x
162 ; CHECK-LABEL: @variadic_can_get_secondIidEEbT_T0_(i32 %x, double %y) {
164 ; CHECK-NEXT: %vararg_buffer = alloca %variadic_can_get_secondIidEEbT_T0_.vararg, align 16
165 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr %vararg_buffer)
166 ; CHECK-NEXT: %0 = getelementptr inbounds %variadic_can_get_secondIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 0
167 ; CHECK-NEXT: store i32 %x, ptr %0, align 4
168 ; CHECK-NEXT: %1 = getelementptr inbounds %variadic_can_get_secondIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 1
169 ; CHECK-NEXT: store double %y, ptr %1, align 4
170 ; CHECK-NEXT: %call = call double @variadic_int_double_get_secondz.valist(ptr %vararg_buffer)
171 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr %vararg_buffer)
172 ; CHECK-NEXT: %cmp.i = fcmp oeq double %call, %y
173 ; CHECK-NEXT: ret i1 %cmp.i
176 define zeroext i1 @variadic_can_get_secondIidEEbT_T0_(i32 %x, double %y) {
177 ; OPT-LABEL: define {{[^@]+}}@variadic_can_get_secondIidEEbT_T0_(i32 %x, double %y) {
179 ; OPT-NEXT: %vararg_buffer = alloca %variadic_can_get_secondIidEEbT_T0_.vararg, align 16
180 ; OPT-NEXT: call void @llvm.lifetime.start.p0(i64 16, ptr %vararg_buffer)
181 ; OPT-NEXT: %0 = getelementptr inbounds nuw %variadic_can_get_secondIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 0
182 ; OPT-NEXT: store i32 %x, ptr %0, align 4
183 ; OPT-NEXT: %1 = getelementptr inbounds nuw %variadic_can_get_secondIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 2
184 ; OPT-NEXT: store double %y, ptr %1, align 8
185 ; OPT-NEXT: %call = call double @variadic_int_double_get_secondz.valist(ptr %vararg_buffer)
186 ; OPT-NEXT: call void @llvm.lifetime.end.p0(i64 16, ptr %vararg_buffer)
187 ; OPT-NEXT: %cmp.i = fcmp oeq double %call, %y
188 ; OPT-NEXT: ret i1 %cmp.i
190 ; ABI-LABEL: define {{[^@]+}}@variadic_can_get_secondIidEEbT_T0_(i32 %x, double %y) {
192 ; ABI-NEXT: %vararg_buffer = alloca %variadic_can_get_secondIidEEbT_T0_.vararg, align 16
193 ; ABI-NEXT: call void @llvm.lifetime.start.p0(i64 16, ptr %vararg_buffer)
194 ; ABI-NEXT: %0 = getelementptr inbounds nuw %variadic_can_get_secondIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 0
195 ; ABI-NEXT: store i32 %x, ptr %0, align 4
196 ; ABI-NEXT: %1 = getelementptr inbounds nuw %variadic_can_get_secondIidEEbT_T0_.vararg, ptr %vararg_buffer, i32 0, i32 2
197 ; ABI-NEXT: store double %y, ptr %1, align 8
198 ; ABI-NEXT: %call = call double @variadic_int_double_get_secondz(ptr %vararg_buffer)
199 ; ABI-NEXT: call void @llvm.lifetime.end.p0(i64 16, ptr %vararg_buffer)
200 ; ABI-NEXT: %cmp.i = fcmp oeq double %call, %y
201 ; ABI-NEXT: ret i1 %cmp.i
204 %call = call double (...) @variadic_int_double_get_secondz(i32 %x, double %y)
205 %cmp.i = fcmp oeq double %call, %y
209 ; Declaration unchanged
210 ; CHECK: declare void @variadic_without_callers(...)
211 declare void @variadic_without_callers(...)
213 declare void @llvm.va_start.p0(ptr)
214 declare void @llvm.va_end.p0(ptr)