Follow up to d0858bffa11, add missing REQUIRES x86
[llvm-project.git] / llvm / test / Transforms / Coroutines / no-suspend.ll
blob53eb98f1273a9908edb75632dab28c56652109b0
1 ; Test no suspend coroutines
2 ; RUN: opt < %s -passes='cgscc(coro-split),simplifycfg,early-cse,simplifycfg' -S | FileCheck %s
4 ; Coroutine with no-suspends will turn into:
6 ; CHECK-LABEL: define void @no_suspends(
7 ; CHECK-NEXT:  entry:
8 ; CHECK-NEXT:    call void @print(i32 %n)
9 ; CHECK-NEXT:    ret void
11 define void @no_suspends(i32 %n) presplitcoroutine {
12 entry:
13   %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
14   %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
15   br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
16 dyn.alloc:
17   %size = call i32 @llvm.coro.size.i32()
18   %alloc = call ptr @malloc(i32 %size)
19   br label %coro.begin
20 coro.begin:
21   %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
22   %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)
23   br label %body
24 body:
25   call void @print(i32 %n)
26   br label %cleanup
27 cleanup:
28   %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)
29   %need.dyn.free = icmp ne ptr %mem, null
30   br i1 %need.dyn.free, label %dyn.free, label %suspend
31 dyn.free:
32   call void @free(ptr %mem)
33   br label %suspend
34 suspend:
35   call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
36   ret void
39 ; SimplifySuspendPoint will detect that coro.resume resumes itself and will
40 ; replace suspend with a jump to %resume label turning it into no-suspend
41 ; coroutine.
43 ; CHECK-LABEL: define void @simplify_resume(
44 ; CHECK-NEXT:  entry:
45 ; CHECK-NEXT:    call void @llvm.memcpy
46 ; CHECK-NEXT:    call void @print(i32 0)
47 ; CHECK-NEXT:    ret void
49 define void @simplify_resume(ptr %src, ptr %dst) presplitcoroutine {
50 entry:
51   %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
52   %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
53   br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
54 dyn.alloc:
55   %size = call i32 @llvm.coro.size.i32()
56   %alloc = call ptr @malloc(i32 %size)
57   br label %coro.begin
58 coro.begin:
59   %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
60   %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)
61   br label %body
62 body:
63   %save = call token @llvm.coro.save(ptr %hdl)
64   ; memcpy intrinsics should not prevent simplification.
65   call void @llvm.memcpy.p0.p0.i64(ptr %dst, ptr %src, i64 1, i1 false)
66   %subfn = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 0)
67   call fastcc void %subfn(ptr %hdl)
68   %0 = call i8 @llvm.coro.suspend(token %save, i1 false)
69   switch i8 %0, label %suspend [i8 0, label %resume
70                                 i8 1, label %pre.cleanup]
71 resume:
72   call void @print(i32 0)
73   br label %cleanup
75 pre.cleanup:
76   call void @print(i32 1)
77   br label %cleanup
79 cleanup:
80   %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)
81   call void @free(ptr %mem)
82   br label %suspend
83 suspend:
84   call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
85   ret void
88 ; SimplifySuspendPoint will detect that coroutine destroys itself and will
89 ; replace suspend with a jump to %cleanup label turning it into no-suspend
90 ; coroutine.
92 ; CHECK-LABEL: define void @simplify_destroy(
93 ; CHECK-NEXT:  entry:
94 ; CHECK-NEXT:    call void @print(i32 1)
95 ; CHECK-NEXT:    ret void
97 define void @simplify_destroy() presplitcoroutine personality i32 0 {
98 entry:
99   %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
100   %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
101   br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
102 dyn.alloc:
103   %size = call i32 @llvm.coro.size.i32()
104   %alloc = call ptr @malloc(i32 %size)
105   br label %coro.begin
106 coro.begin:
107   %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
108   %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)
109   br label %body
110 body:
111   %save = call token @llvm.coro.save(ptr %hdl)
112   %subfn = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)
113   invoke fastcc void %subfn(ptr %hdl) to label %real_susp unwind label %lpad
115 real_susp:
116   %0 = call i8 @llvm.coro.suspend(token %save, i1 false)
117   switch i8 %0, label %suspend [i8 0, label %resume
118                                 i8 1, label %pre.cleanup]
119 resume:
120   call void @print(i32 0)
121   br label %cleanup
123 pre.cleanup:
124   call void @print(i32 1)
125   br label %cleanup
127 cleanup:
128   %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)
129   call void @free(ptr %mem)
130   br label %suspend
131 suspend:
132   call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
133   ret void
134 lpad:
135   %lpval = landingpad { ptr, i32 }
136      cleanup
138   call void @print(i32 2)
139   resume { ptr, i32 } %lpval
142 ; SimplifySuspendPoint will detect that coro.resume resumes itself and will
143 ; replace suspend with a jump to %resume label turning it into no-suspend
144 ; coroutine.
146 ; CHECK-LABEL: define void @simplify_resume_with_inlined_if(
147 ; CHECK-NEXT:  entry:
148 ; CHECK-NEXT:    br i1
149 ; CHECK:         call void @print(i32 0)
150 ; CHECK-NEXT:    ret void
152 define void @simplify_resume_with_inlined_if(ptr %src, ptr %dst, i1 %cond) presplitcoroutine {
153 entry:
154   %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
155   %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
156   br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
157 dyn.alloc:
158   %size = call i32 @llvm.coro.size.i32()
159   %alloc = call ptr @malloc(i32 %size)
160   br label %coro.begin
161 coro.begin:
162   %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
163   %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)
164   br label %body
165 body:
166   %save = call token @llvm.coro.save(ptr %hdl)
167   br i1 %cond, label %if.then, label %if.else
168 if.then:
169   call void @llvm.memcpy.p0.p0.i64(ptr %dst, ptr %src, i64 1, i1 false)
170   br label %if.end
171 if.else:
172   call void @llvm.memcpy.p0.p0.i64(ptr %src, ptr %dst, i64 1, i1 false)
173   br label %if.end
174 if.end:
175   %subfn = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 0)
176   call fastcc void %subfn(ptr %hdl)
177   %0 = call i8 @llvm.coro.suspend(token %save, i1 false)
178   switch i8 %0, label %suspend [i8 0, label %resume
179                                 i8 1, label %pre.cleanup]
180 resume:
181   call void @print(i32 0)
182   br label %cleanup
184 pre.cleanup:
185   call void @print(i32 1)
186   br label %cleanup
188 cleanup:
189   %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)
190   call void @free(ptr %mem)
191   br label %suspend
192 suspend:
193   call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
194   ret void
199 ; SimplifySuspendPoint won't be able to simplify if it detects that there are
200 ; other calls between coro.save and coro.suspend. They potentially can call
201 ; resume or destroy, so we should not simplify this suspend point.
203 ; CHECK-LABEL: define void @cannot_simplify_other_calls(
204 ; CHECK-NEXT:  entry:
205 ; CHECK-NEXT:     llvm.coro.id
207 define void @cannot_simplify_other_calls() presplitcoroutine {
208 entry:
209   %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
210   %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
211   br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
212 dyn.alloc:
213   %size = call i32 @llvm.coro.size.i32()
214   %alloc = call ptr @malloc(i32 %size)
215   br label %coro.begin
216 coro.begin:
217   %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
218   %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)
219   br label %body
220 body:
221   %save = call token @llvm.coro.save(ptr %hdl)
222   br label %body1
224 body1:
225   call void @foo()
226   br label %body2
228 body2:
229   %subfn = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)
230   call fastcc void %subfn(ptr %hdl)
231   %0 = call i8 @llvm.coro.suspend(token %save, i1 false)
232   switch i8 %0, label %suspend [i8 0, label %resume
233                                 i8 1, label %pre.cleanup]
234 resume:
235   call void @print(i32 0)
236   br label %cleanup
238 pre.cleanup:
239   call void @print(i32 1)
240   br label %cleanup
242 cleanup:
243   %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)
244   call void @free(ptr %mem)
245   br label %suspend
246 suspend:
247   call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
248   ret void
251 ; SimplifySuspendPoint won't be able to simplify if it detects that there are
252 ; other calls between coro.save and coro.suspend. They potentially can call
253 ; resume or destroy, so we should not simplify this suspend point.
255 ; CHECK-LABEL: define void @cannot_simplify_calls_in_terminator(
256 ; CHECK-NEXT:  entry:
257 ; CHECK-NEXT:     llvm.coro.id
259 define void @cannot_simplify_calls_in_terminator() presplitcoroutine personality i32 0 {
260 entry:
261   %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
262   %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
263   br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
264 dyn.alloc:
265   %size = call i32 @llvm.coro.size.i32()
266   %alloc = call ptr @malloc(i32 %size)
267   br label %coro.begin
268 coro.begin:
269   %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
270   %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)
271   br label %body
272 body:
273   %save = call token @llvm.coro.save(ptr %hdl)
274   invoke void @foo() to label %resume_cont unwind label %lpad
275 resume_cont:
276   %subfn = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)
277   call fastcc void %subfn(ptr %hdl)
278   %0 = call i8 @llvm.coro.suspend(token %save, i1 false)
279   switch i8 %0, label %suspend [i8 0, label %resume
280                                 i8 1, label %pre.cleanup]
281 resume:
282   call void @print(i32 0)
283   br label %cleanup
285 pre.cleanup:
286   call void @print(i32 1)
287   br label %cleanup
289 cleanup:
290   %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)
291   call void @free(ptr %mem)
292   br label %suspend
293 suspend:
294   call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
295   ret void
296 lpad:
297   %lpval = landingpad { ptr, i32 }
298      cleanup
300   call void @print(i32 2)
301   resume { ptr, i32 } %lpval
304 ; SimplifySuspendPoint won't be able to simplify if it detects that resume or
305 ; destroy does not immediately preceed coro.suspend.
307 ; CHECK-LABEL: define void @cannot_simplify_not_last_instr(
308 ; CHECK-NEXT:  entry:
309 ; CHECK-NEXT:     llvm.coro.id
311 define void @cannot_simplify_not_last_instr(ptr %dst, ptr %src) presplitcoroutine {
312 entry:
313   %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
314   %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
315   br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
316 dyn.alloc:
317   %size = call i32 @llvm.coro.size.i32()
318   %alloc = call ptr @malloc(i32 %size)
319   br label %coro.begin
320 coro.begin:
321   %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
322   %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)
323   br label %body
324 body:
325   %save = call token @llvm.coro.save(ptr %hdl)
326   %subfn = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)
327   call fastcc void %subfn(ptr %hdl)
328   ; memcpy separates destory from suspend, therefore cannot simplify.
329   call void @llvm.memcpy.p0.p0.i64(ptr %dst, ptr %src, i64 1, i1 false)
330   %0 = call i8 @llvm.coro.suspend(token %save, i1 false)
331   switch i8 %0, label %suspend [i8 0, label %resume
332                                 i8 1, label %pre.cleanup]
333 resume:
334   call void @print(i32 0)
335   br label %cleanup
337 pre.cleanup:
338   call void @print(i32 1)
339   br label %cleanup
341 cleanup:
342   %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)
343   call void @free(ptr %mem)
344   br label %suspend
345 suspend:
346   call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
347   ret void
350 ; SimplifySuspendPoint should not simplify final suspend point
352 ; CHECK-LABEL: define void @cannot_simplify_final_suspend(
353 ; CHECK-NEXT:  entry:
354 ; CHECK-NEXT:     llvm.coro.id
356 define void @cannot_simplify_final_suspend() presplitcoroutine personality i32 0 {
357 entry:
358   %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
359   %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
360   br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
361 dyn.alloc:
362   %size = call i32 @llvm.coro.size.i32()
363   %alloc = call ptr @malloc(i32 %size)
364   br label %coro.begin
365 coro.begin:
366   %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
367   %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)
368   br label %body
369 body:
370   %save = call token @llvm.coro.save(ptr %hdl)
371   %subfn = call ptr @llvm.coro.subfn.addr(ptr %hdl, i8 1)
372   invoke fastcc void %subfn(ptr %hdl) to label %real_susp unwind label %lpad
374 real_susp:
375   %0 = call i8 @llvm.coro.suspend(token %save, i1 1)
376   switch i8 %0, label %suspend [i8 0, label %resume
377                                 i8 1, label %pre.cleanup]
378 resume:
379   call void @print(i32 0)
380   br label %cleanup
382 pre.cleanup:
383   call void @print(i32 1)
384   br label %cleanup
386 cleanup:
387   %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)
388   call void @free(ptr %mem)
389   br label %suspend
390 suspend:
391   call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
392   ret void
393 lpad:
394   %lpval = landingpad { ptr, i32 }
395      cleanup
397   call void @print(i32 2)
398   resume { ptr, i32 } %lpval
401 declare ptr @malloc(i32) allockind("alloc,uninitialized") allocsize(0)
402 declare void @free(ptr) willreturn allockind("free")
403 declare void @print(i32)
404 declare void @foo()
406 declare token @llvm.coro.id(i32, ptr, ptr, ptr)
407 declare i1 @llvm.coro.alloc(token)
408 declare i32 @llvm.coro.size.i32()
409 declare ptr @llvm.coro.begin(token, ptr)
410 declare token @llvm.coro.save(ptr %hdl)
411 declare i8 @llvm.coro.suspend(token, i1)
412 declare ptr @llvm.coro.free(token, ptr)
413 declare i1 @llvm.coro.end(ptr, i1, token)
415 declare ptr @llvm.coro.subfn.addr(ptr, i8)
417 declare void @llvm.memcpy.p0.p0.i64(ptr nocapture writeonly, ptr nocapture readonly, i64, i1)