Bump version to 19.1.0-rc3
[llvm-project.git] / llvm / test / Transforms / Coroutines / coro-heap-elide.ll
blob633045d4c9b83bd857554edce1127e2ffcccf39c
1 ; Tests that the dynamic allocation and deallocation of the coroutine frame is
2 ; elided and any tail calls referencing the coroutine frame has the tail
3 ; call attribute removed.
4 ; RUN: opt < %s -S \
5 ; RUN: -passes='cgscc(inline,function(coro-elide,instsimplify,simplifycfg))' \
6 ; RUN:   -aa-pipeline='basic-aa' | FileCheck %s
8 declare void @print(i32) nounwind
10 %f.frame = type {i32}
12 declare void @bar(ptr)
14 declare fastcc void @f.resume(ptr align 4 dereferenceable(4))
15 declare fastcc void @f.destroy(ptr)
16 declare fastcc void @f.cleanup(ptr)
18 declare void @may_throw()
19 declare ptr @CustomAlloc(i32)
20 declare void @CustomFree(ptr)
22 @f.resumers = internal constant [3 x ptr]
23   [ptr @f.resume, ptr @f.destroy, ptr @f.cleanup]
25 ; a coroutine start function
26 define ptr @f() personality ptr null {
27 entry:
28   %id = call token @llvm.coro.id(i32 0, ptr null,
29                       ptr @f,
30                       ptr @f.resumers)
31   %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
32   br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
33 dyn.alloc:
34   %alloc = call ptr @CustomAlloc(i32 4)
35   br label %coro.begin
36 coro.begin:
37   %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
38   %hdl = call ptr @llvm.coro.begin(token %id, ptr %phi)
39   invoke void @may_throw()
40     to label %ret unwind label %ehcleanup
41 ret:
42   ret ptr %hdl
44 ehcleanup:
45   %tok = cleanuppad within none []
46   %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)
47   %need.dyn.free = icmp ne ptr %mem, null
48   br i1 %need.dyn.free, label %dyn.free, label %if.end
49 dyn.free:
50   call void @CustomFree(ptr %mem)
51   br label %if.end
52 if.end:
53   cleanupret from %tok unwind to caller
56 ; CHECK-LABEL: @callResume(
57 define void @callResume() {
58 entry:
59 ; CHECK: alloca [4 x i8], align 4
60 ; CHECK-NOT: coro.begin
61 ; CHECK-NOT: CustomAlloc
62 ; CHECK: call void @may_throw()
63   %hdl = call ptr @f()
65 ; Need to remove 'tail' from the first call to @bar
66 ; CHECK-NOT: tail call void @bar(
67 ; CHECK: call void @bar(
68   tail call void @bar(ptr %hdl)
69 ; CHECK: tail call void @bar(
70   tail call void @bar(ptr null)
72 ; CHECK-NEXT: call fastcc void @f.resume(ptr %0)
73   %0 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 0)
74   call fastcc void %0(ptr %hdl)
76 ; CHECK-NEXT: call fastcc void @f.cleanup(ptr %0)
77   %1 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)
78   call fastcc void %1(ptr %hdl)
80 ; CHECK-NEXT: ret void
81   ret void
84 ; CHECK-LABEL: @callResume_with_coro_suspend_1(
85 define void @callResume_with_coro_suspend_1() {
86 entry:
87 ; CHECK: alloca [4 x i8], align 4
88 ; CHECK-NOT: coro.begin
89 ; CHECK-NOT: CustomAlloc
90 ; CHECK: call void @may_throw()
91   %hdl = call ptr @f()
93 ; CHECK-NEXT: call fastcc void @f.resume(ptr %0)
94   %0 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 0)
95   call fastcc void %0(ptr %hdl)
96   %1 = call token @llvm.coro.save(ptr %hdl)
97   %2 = call i8 @llvm.coro.suspend(token %1, i1 false)
98   switch i8 %2, label  %coro.ret [
99     i8 0, label %final.suspend
100     i8 1, label %cleanups
101   ]
103 ; CHECK-LABEL: final.suspend:
104 final.suspend:
105 ; CHECK-NEXT: call fastcc void @f.cleanup(ptr %0)
106   %3 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)
107   call fastcc void %3(ptr %hdl)
108   %4 = call token @llvm.coro.save(ptr %hdl)
109   %5 = call i8 @llvm.coro.suspend(token %4, i1 true)
110   switch i8 %5, label  %coro.ret [
111     i8 0, label %coro.ret
112     i8 1, label %cleanups
113   ]
115 ; CHECK-LABEL: cleanups:
116 cleanups:
117 ; CHECK-NEXT: call fastcc void @f.cleanup(ptr %0)
118   %6 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)
119   call fastcc void %6(ptr %hdl)
120   br label %coro.ret
122 ; CHECK-LABEL: coro.ret:
123 coro.ret:
124 ; CHECK-NEXT: ret void
125   ret void
128 ; CHECK-LABEL: @callResume_with_coro_suspend_2(
129 define void @callResume_with_coro_suspend_2() personality ptr null {
130 entry:
131 ; CHECK: alloca [4 x i8], align 4
132 ; CHECK-NOT: coro.begin
133 ; CHECK-NOT: CustomAlloc
134 ; CHECK: call void @may_throw()
135   %hdl = call ptr @f()
137   %0 = call token @llvm.coro.save(ptr %hdl)
138 ; CHECK: invoke fastcc void @f.resume(ptr %0)
139   %1 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 0)
140   invoke fastcc void %1(ptr %hdl)
141     to label %invoke.cont1 unwind label %lpad
143 ; CHECK-LABEL: invoke.cont1:
144 invoke.cont1:
145   %2 = call i8 @llvm.coro.suspend(token %0, i1 false)
146   switch i8 %2, label  %coro.ret [
147     i8 0, label %final.ready
148     i8 1, label %cleanups
149   ]
151 ; CHECK-LABEL: lpad:
152 lpad:
153   %3 = landingpad { ptr, i32 }
154           catch ptr null
155 ; CHECK: call fastcc void @f.cleanup(ptr %0)
156   %4 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)
157   call fastcc void %4(ptr %hdl)
158   br label %final.suspend
160 ; CHECK-LABEL: final.ready:
161 final.ready:
162 ; CHECK-NEXT: call fastcc void @f.cleanup(ptr %0)
163   %5 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)
164   call fastcc void %5(ptr %hdl)
165   br label %final.suspend
167 ; CHECK-LABEL: final.suspend:
168 final.suspend:
169   %6 = call token @llvm.coro.save(ptr %hdl)
170   %7 = call i8 @llvm.coro.suspend(token %6, i1 true)
171   switch i8 %7, label  %coro.ret [
172     i8 0, label %coro.ret
173     i8 1, label %cleanups
174   ]
176 ; CHECK-LABEL: cleanups:
177 cleanups:
178 ; CHECK-NEXT: call fastcc void @f.cleanup(ptr %0)
179   %8 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)
180   call fastcc void %8(ptr %hdl)
181   br label %coro.ret
183 ; CHECK-LABEL: coro.ret:
184 coro.ret:
185 ; CHECK-NEXT: ret void
186   ret void
189 ; CHECK-LABEL: @callResume_with_coro_suspend_3(
190 define void @callResume_with_coro_suspend_3(i8 %cond) {
191 entry:
192 ; CHECK: alloca [4 x i8], align 4
193   switch i8 %cond, label  %coro.ret [
194     i8 0, label %init.suspend
195     i8 1, label %coro.ret
196   ]
198 init.suspend:
199 ; CHECK-NOT: llvm.coro.begin
200 ; CHECK-NOT: CustomAlloc
201 ; CHECK: call void @may_throw()
202   %hdl = call ptr @f()
203 ; CHECK-NEXT: call fastcc void @f.resume(ptr %0)
204   %0 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 0)
205   call fastcc void %0(ptr %hdl)
206   %1 = call token @llvm.coro.save(ptr %hdl)
207   %2 = call i8 @llvm.coro.suspend(token %1, i1 false)
208   switch i8 %2, label  %coro.ret [
209     i8 0, label %final.suspend
210     i8 1, label %cleanups
211   ]
213 ; CHECK-LABEL: final.suspend:
214 final.suspend:
215 ; CHECK-NEXT: call fastcc void @f.cleanup(ptr %0)
216   %3 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)
217   call fastcc void %3(ptr %hdl)
218   %4 = call token @llvm.coro.save(ptr %hdl)
219   %5 = call i8 @llvm.coro.suspend(token %4, i1 true)
220   switch i8 %5, label  %coro.ret [
221     i8 0, label %coro.ret
222     i8 1, label %cleanups
223   ]
225 ; CHECK-LABEL: cleanups:
226 cleanups:
227 ; CHECK-NEXT: call fastcc void @f.cleanup(ptr %0)
228   %6 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)
229   call fastcc void %6(ptr %hdl)
230   br label %coro.ret
232 ; CHECK-LABEL: coro.ret:
233 coro.ret:
234 ; CHECK-NEXT: ret void
235   ret void
240 ; CHECK-LABEL: @callResume_PR34897_no_elision(
241 define void @callResume_PR34897_no_elision(i1 %cond) {
242 ; CHECK-LABEL: entry:
243 entry:
244 ; CHECK: call ptr @CustomAlloc(
245   %hdl = call ptr @f()
246 ; CHECK: tail call void @bar(
247   tail call void @bar(ptr %hdl)
248 ; CHECK: tail call void @bar(
249   tail call void @bar(ptr null)
250   br i1 %cond, label %if.then, label %if.else
252 ; CHECK-LABEL: if.then:
253 if.then:
254 ; CHECK: call fastcc void @f.resume(ptr
255   %0 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 0)
256   call fastcc void %0(ptr %hdl)
257 ; CHECK-NEXT: call fastcc void @f.destroy(ptr
258   %1 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)
259   call fastcc void %1(ptr %hdl)
260   br label %return
262 if.else:
263   br label %return
265 ; CHECK-LABEL: return:
266 return:
267 ; CHECK: ret void
268   ret void
271 ; CHECK-LABEL: @callResume_PR34897_elision(
272 define void @callResume_PR34897_elision(i1 %cond) {
273 ; CHECK-LABEL: entry:
274 entry:
275 ; CHECK: alloca [4 x i8], align 4
276 ; CHECK: tail call void @bar(
277   tail call void @bar(ptr null)
278   br i1 %cond, label %if.then, label %if.else
280 if.then:
281 ; CHECK-NOT: CustomAlloc
282 ; CHECK: call void @may_throw()
283   %hdl = call ptr @f()
284 ; CHECK: call void @bar(
285   tail call void @bar(ptr %hdl)
286 ; CHECK: call fastcc void @f.resume(ptr
287   %0 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 0)
288   call fastcc void %0(ptr %hdl)
289 ; CHECK-NEXT: call fastcc void @f.cleanup(ptr
290   %1 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)
291   call fastcc void %1(ptr %hdl)
292   br label %return
294 if.else:
295   br label %return
297 ; CHECK-LABEL: return:
298 return:
299 ; CHECK: ret void
300   ret void
304 ; a coroutine start function (cannot elide heap alloc, due to second argument to
305 ; coro.begin not pointint to coro.alloc)
306 define ptr @f_no_elision() personality ptr null {
307 entry:
308   %id = call token @llvm.coro.id(i32 0, ptr null,
309                       ptr @f_no_elision,
310                       ptr @f.resumers)
311   %alloc = call ptr @CustomAlloc(i32 4)
312   %hdl = call ptr @llvm.coro.begin(token %id, ptr %alloc)
313   ret ptr %hdl
316 ; CHECK-LABEL: @callResume_no_elision(
317 define void @callResume_no_elision() {
318 entry:
319 ; CHECK: call ptr @CustomAlloc(
320   %hdl = call ptr @f_no_elision()
322 ; Tail call should remain tail calls
323 ; CHECK: tail call void @bar(
324   tail call void @bar(ptr %hdl)
325 ; CHECK: tail call void @bar(
326   tail call void @bar(ptr null)
328 ; CHECK-NEXT: call fastcc void @f.resume(ptr
329   %0 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 0)
330   call fastcc void %0(ptr %hdl)
332 ; CHECK-NEXT: call fastcc void @f.destroy(ptr
333   %1 = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)
334   call fastcc void %1(ptr %hdl)
336 ; CHECK-NEXT: ret void
337   ret void
340 declare token @llvm.coro.id(i32, ptr, ptr, ptr)
341 declare i1 @llvm.coro.alloc(token)
342 declare ptr @llvm.coro.free(token, ptr)
343 declare ptr @llvm.coro.begin(token, ptr)
344 declare ptr @llvm.coro.frame(token)
345 declare ptr @llvm.coro.subfn.addr(ptr, i8)
346 declare i8 @llvm.coro.suspend(token, i1)
347 declare token @llvm.coro.save(ptr)