xref: /llvm-project/llvm/test/Transforms/ExpandVariadics/expand-va-intrinsic-split-simple.ll (revision 94473f4db6a6f5f12d7c4081455b5b596094eac5)
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
5
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
8
9define i32 @variadic_int_double_get_firstz(...) {
10; OPT-LABEL: define {{[^@]+}}@variadic_int_double_get_firstz(...) {
11; OPT-NEXT:  entry:
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
19;
20; ABI-LABEL: define {{[^@]+}}@variadic_int_double_get_firstz(ptr %varargs) {
21; ABI-NEXT:  entry:
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
29;
30entry:
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)
38  ret i32 %0
39}
40
41; CHECK-LABEL: define i32 @variadic_int_double_get_firstz(...) {
42; CHECK-NEXT:  entry:
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
47; CHECK-NEXT:  }
48
49; CHECK-LABEL: define internal i32 @variadic_int_double_get_firstz.valist(ptr noalias %varargs) {
50; CHECK-NEXT:  entry:
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
58; CHECK-NEXT:  }
59
60define double @variadic_int_double_get_secondz(...) {
61; OPT-LABEL: define {{[^@]+}}@variadic_int_double_get_secondz(...) {
62; OPT-NEXT:  entry:
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
70;
71; ABI-LABEL: define {{[^@]+}}@variadic_int_double_get_secondz(ptr %varargs) {
72; ABI-NEXT:  entry:
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
81;
82entry:
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)
91  ret double %0
92}
93
94; CHECK-LABEL: define double @variadic_int_double_get_secondz(...) {
95; CHECK-NEXT:  entry:
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
100; CHECK-NEXT:  }
101
102; CHECK-LABEL: define internal double @variadic_int_double_get_secondz.valist(ptr noalias %varargs) {
103; CHECK-NEXT:  entry:
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
112; CHECK-NEXT:  }
113
114
115; CHECK-LABEL: @variadic_can_get_firstIidEEbT_T0_(i32 %x, double %y) {
116; CHECK-NEXT:  entry:
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
127; CHECK-NEXT:  }
128
129define zeroext i1 @variadic_can_get_firstIidEEbT_T0_(i32 %x, double %y) {
130; OPT-LABEL: define {{[^@]+}}@variadic_can_get_firstIidEEbT_T0_(i32 %x, double %y) {
131; OPT-NEXT:  entry:
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
142;
143; ABI-LABEL: define {{[^@]+}}@variadic_can_get_firstIidEEbT_T0_(i32 %x, double %y) {
144; ABI-NEXT:  entry:
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
155;
156entry:
157  %call = call i32 (...) @variadic_int_double_get_firstz(i32 %x, double %y)
158  %cmp.i = icmp eq i32 %call, %x
159  ret i1 %cmp.i
160}
161
162; CHECK-LABEL: @variadic_can_get_secondIidEEbT_T0_(i32 %x, double %y) {
163; CHECK-NEXT:  entry:
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
174; CHECK-NEXT:  }
175
176define zeroext i1 @variadic_can_get_secondIidEEbT_T0_(i32 %x, double %y) {
177; OPT-LABEL: define {{[^@]+}}@variadic_can_get_secondIidEEbT_T0_(i32 %x, double %y) {
178; OPT-NEXT:  entry:
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
189;
190; ABI-LABEL: define {{[^@]+}}@variadic_can_get_secondIidEEbT_T0_(i32 %x, double %y) {
191; ABI-NEXT:  entry:
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
202;
203entry:
204  %call = call double (...) @variadic_int_double_get_secondz(i32 %x, double %y)
205  %cmp.i = fcmp oeq double %call, %y
206  ret i1 %cmp.i
207}
208
209; Declaration unchanged
210; CHECK: declare void @variadic_without_callers(...)
211declare void @variadic_without_callers(...)
212
213declare void @llvm.va_start.p0(ptr)
214declare void @llvm.va_end.p0(ptr)
215