[InstCombine] Signed saturation tests. NFC
[llvm-complete.git] / test / Transforms / Coroutines / no-suspend.ll
blobfca096fa48bb39df14dc703a4f11c22df9cc2580
1 ; Test no suspend coroutines
2 ; RUN: opt < %s -coro-split -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:    alloca
9 ; CHECK-NEXT:    bitcast
10 ; CHECK-NEXT:    call void @print(i32 %n)
11 ; CHECK-NEXT:    ret void
13 define void @no_suspends(i32 %n) "coroutine.presplit"="1" {
14 entry:
15   %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
16   %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
17   br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
18 dyn.alloc:
19   %size = call i32 @llvm.coro.size.i32()
20   %alloc = call i8* @malloc(i32 %size)
21   br label %coro.begin
22 coro.begin:
23   %phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ]
24   %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %phi)
25   br label %body
26 body:
27   call void @print(i32 %n)
28   br label %cleanup
29 cleanup:
30   %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
31   %need.dyn.free = icmp ne i8* %mem, null
32   br i1 %need.dyn.free, label %dyn.free, label %suspend
33 dyn.free:
34   call void @free(i8* %mem)
35   br label %suspend
36 suspend:
37   call i1 @llvm.coro.end(i8* %hdl, i1 false)
38   ret void
41 ; SimplifySuspendPoint will detect that coro.resume resumes itself and will
42 ; replace suspend with a jump to %resume label turning it into no-suspend
43 ; coroutine.
45 ; CHECK-LABEL: define void @simplify_resume(
46 ; CHECK-NEXT:  entry:
47 ; CHECK-NEXT:    alloca
48 ; CHECK-NEXT:    bitcast
49 ; CHECK-NEXT:    call void @llvm.memcpy
50 ; CHECK-NEXT:    call void @print(i32 0)
51 ; CHECK-NEXT:    ret void
53 define void @simplify_resume(i8* %src, i8* %dst) "coroutine.presplit"="1" {
54 entry:
55   %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
56   %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
57   br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
58 dyn.alloc:
59   %size = call i32 @llvm.coro.size.i32()
60   %alloc = call i8* @malloc(i32 %size)
61   br label %coro.begin
62 coro.begin:
63   %phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ]
64   %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %phi)
65   br label %body
66 body:
67   %save = call token @llvm.coro.save(i8* %hdl)
68   ; memcpy intrinsics should not prevent simplification.
69   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 1, i1 false)
70   %subfn = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0)
71   %bres = bitcast i8* %subfn to void (i8*)*
72   call fastcc void %bres(i8* %hdl)
73   %0 = call i8 @llvm.coro.suspend(token %save, i1 false)
74   switch i8 %0, label %suspend [i8 0, label %resume
75                                 i8 1, label %pre.cleanup]
76 resume:
77   call void @print(i32 0)
78   br label %cleanup
80 pre.cleanup:
81   call void @print(i32 1)
82   br label %cleanup
84 cleanup:
85   %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
86   call void @free(i8* %mem)
87   br label %suspend
88 suspend:
89   call i1 @llvm.coro.end(i8* %hdl, i1 false)
90   ret void
93 ; SimplifySuspendPoint will detect that coroutine destroys itself and will
94 ; replace suspend with a jump to %cleanup label turning it into no-suspend
95 ; coroutine.
97 ; CHECK-LABEL: define void @simplify_destroy(
98 ; CHECK-NEXT:  entry:
99 ; CHECK-NEXT:    alloca
100 ; CHECK-NEXT:    bitcast
101 ; CHECK-NEXT:    call void @print(i32 1)
102 ; CHECK-NEXT:    ret void
104 define void @simplify_destroy() "coroutine.presplit"="1" personality i32 0 {
105 entry:
106   %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
107   %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
108   br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
109 dyn.alloc:
110   %size = call i32 @llvm.coro.size.i32()
111   %alloc = call i8* @malloc(i32 %size)
112   br label %coro.begin
113 coro.begin:
114   %phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ]
115   %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %phi)
116   br label %body
117 body:
118   %save = call token @llvm.coro.save(i8* %hdl)
119   %subfn = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1)
120   %bcast = bitcast i8* %subfn to void (i8*)*
121   invoke fastcc void %bcast(i8* %hdl) to label %real_susp unwind label %lpad
123 real_susp:
124   %0 = call i8 @llvm.coro.suspend(token %save, i1 false)
125   switch i8 %0, label %suspend [i8 0, label %resume
126                                 i8 1, label %pre.cleanup]
127 resume:
128   call void @print(i32 0)
129   br label %cleanup
131 pre.cleanup:
132   call void @print(i32 1)
133   br label %cleanup
135 cleanup:
136   %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
137   call void @free(i8* %mem)
138   br label %suspend
139 suspend:
140   call i1 @llvm.coro.end(i8* %hdl, i1 false)
141   ret void
142 lpad:
143   %lpval = landingpad { i8*, i32 }
144      cleanup
146   call void @print(i32 2)
147   resume { i8*, i32 } %lpval
150 ; SimplifySuspendPoint will detect that coro.resume resumes itself and will
151 ; replace suspend with a jump to %resume label turning it into no-suspend
152 ; coroutine.
154 ; CHECK-LABEL: define void @simplify_resume_with_inlined_if(
155 ; CHECK-NEXT:  entry:
156 ; CHECK-NEXT:    alloca
157 ; CHECK-NEXT:    bitcast
158 ; CHECK-NEXT:    br i1
159 ; CHECK:         call void @print(i32 0)
160 ; CHECK-NEXT:    ret void
162 define void @simplify_resume_with_inlined_if(i8* %src, i8* %dst, i1 %cond) "coroutine.presplit"="1" {
163 entry:
164   %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
165   %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
166   br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
167 dyn.alloc:
168   %size = call i32 @llvm.coro.size.i32()
169   %alloc = call i8* @malloc(i32 %size)
170   br label %coro.begin
171 coro.begin:
172   %phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ]
173   %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %phi)
174   br label %body
175 body:
176   %save = call token @llvm.coro.save(i8* %hdl)
177   br i1 %cond, label %if.then, label %if.else
178 if.then:
179   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 1, i1 false)
180   br label %if.end
181 if.else:
182   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %src, i8* %dst, i64 1, i1 false)
183   br label %if.end
184 if.end:
185   %subfn = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0)
186   %bres = bitcast i8* %subfn to void (i8*)*
187   call fastcc void %bres(i8* %hdl)
188   %0 = call i8 @llvm.coro.suspend(token %save, i1 false)
189   switch i8 %0, label %suspend [i8 0, label %resume
190                                 i8 1, label %pre.cleanup]
191 resume:
192   call void @print(i32 0)
193   br label %cleanup
195 pre.cleanup:
196   call void @print(i32 1)
197   br label %cleanup
199 cleanup:
200   %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
201   call void @free(i8* %mem)
202   br label %suspend
203 suspend:
204   call i1 @llvm.coro.end(i8* %hdl, i1 false)
205   ret void
210 ; SimplifySuspendPoint won't be able to simplify if it detects that there are
211 ; other calls between coro.save and coro.suspend. They potentially can call
212 ; resume or destroy, so we should not simplify this suspend point.
214 ; CHECK-LABEL: define void @cannot_simplify_other_calls(
215 ; CHECK-NEXT:  entry:
216 ; CHECK-NEXT:     llvm.coro.id
218 define void @cannot_simplify_other_calls() "coroutine.presplit"="1" {
219 entry:
220   %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
221   %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
222   br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
223 dyn.alloc:
224   %size = call i32 @llvm.coro.size.i32()
225   %alloc = call i8* @malloc(i32 %size)
226   br label %coro.begin
227 coro.begin:
228   %phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ]
229   %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %phi)
230   br label %body
231 body:
232   %save = call token @llvm.coro.save(i8* %hdl)
233   br label %body1
235 body1:
236   call void @foo()
237   br label %body2
239 body2:
240   %subfn = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1)
241   %bcast = bitcast i8* %subfn to void (i8*)*
242   call fastcc void %bcast(i8* %hdl)
243   %0 = call i8 @llvm.coro.suspend(token %save, i1 false)
244   switch i8 %0, label %suspend [i8 0, label %resume
245                                 i8 1, label %pre.cleanup]
246 resume:
247   call void @print(i32 0)
248   br label %cleanup
250 pre.cleanup:
251   call void @print(i32 1)
252   br label %cleanup
254 cleanup:
255   %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
256   call void @free(i8* %mem)
257   br label %suspend
258 suspend:
259   call i1 @llvm.coro.end(i8* %hdl, i1 false)
260   ret void
263 ; SimplifySuspendPoint won't be able to simplify if it detects that there are
264 ; other calls between coro.save and coro.suspend. They potentially can call
265 ; resume or destroy, so we should not simplify this suspend point.
267 ; CHECK-LABEL: define void @cannot_simplify_calls_in_terminator(
268 ; CHECK-NEXT:  entry:
269 ; CHECK-NEXT:     llvm.coro.id
271 define void @cannot_simplify_calls_in_terminator() "coroutine.presplit"="1" personality i32 0 {
272 entry:
273   %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
274   %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
275   br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
276 dyn.alloc:
277   %size = call i32 @llvm.coro.size.i32()
278   %alloc = call i8* @malloc(i32 %size)
279   br label %coro.begin
280 coro.begin:
281   %phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ]
282   %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %phi)
283   br label %body
284 body:
285   %save = call token @llvm.coro.save(i8* %hdl)
286   invoke void @foo() to label %resume_cont unwind label %lpad
287 resume_cont:
288   %subfn = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1)
289   %bcast = bitcast i8* %subfn to void (i8*)*
290   call fastcc void %bcast(i8* %hdl)
291   %0 = call i8 @llvm.coro.suspend(token %save, i1 false)
292   switch i8 %0, label %suspend [i8 0, label %resume
293                                 i8 1, label %pre.cleanup]
294 resume:
295   call void @print(i32 0)
296   br label %cleanup
298 pre.cleanup:
299   call void @print(i32 1)
300   br label %cleanup
302 cleanup:
303   %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
304   call void @free(i8* %mem)
305   br label %suspend
306 suspend:
307   call i1 @llvm.coro.end(i8* %hdl, i1 false)
308   ret void
309 lpad:
310   %lpval = landingpad { i8*, i32 }
311      cleanup
313   call void @print(i32 2)
314   resume { i8*, i32 } %lpval
317 ; SimplifySuspendPoint won't be able to simplify if it detects that resume or
318 ; destroy does not immediately preceed coro.suspend.
320 ; CHECK-LABEL: define void @cannot_simplify_not_last_instr(
321 ; CHECK-NEXT:  entry:
322 ; CHECK-NEXT:     llvm.coro.id
324 define void @cannot_simplify_not_last_instr(i8* %dst, i8* %src) "coroutine.presplit"="1" {
325 entry:
326   %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
327   %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
328   br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
329 dyn.alloc:
330   %size = call i32 @llvm.coro.size.i32()
331   %alloc = call i8* @malloc(i32 %size)
332   br label %coro.begin
333 coro.begin:
334   %phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ]
335   %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %phi)
336   br label %body
337 body:
338   %save = call token @llvm.coro.save(i8* %hdl)
339   %subfn = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1)
340   %bcast = bitcast i8* %subfn to void (i8*)*
341   call fastcc void %bcast(i8* %hdl)
342   ; memcpy separates destory from suspend, therefore cannot simplify.
343   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 1, i1 false)
344   %0 = call i8 @llvm.coro.suspend(token %save, i1 false)
345   switch i8 %0, label %suspend [i8 0, label %resume
346                                 i8 1, label %pre.cleanup]
347 resume:
348   call void @print(i32 0)
349   br label %cleanup
351 pre.cleanup:
352   call void @print(i32 1)
353   br label %cleanup
355 cleanup:
356   %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
357   call void @free(i8* %mem)
358   br label %suspend
359 suspend:
360   call i1 @llvm.coro.end(i8* %hdl, i1 false)
361   ret void
364 declare i8* @malloc(i32)
365 declare void @free(i8*)
366 declare void @print(i32)
367 declare void @foo()
369 declare token @llvm.coro.id(i32, i8*, i8*, i8*)
370 declare i1 @llvm.coro.alloc(token)
371 declare i32 @llvm.coro.size.i32()
372 declare i8* @llvm.coro.begin(token, i8*)
373 declare token @llvm.coro.save(i8* %hdl)
374 declare i8 @llvm.coro.suspend(token, i1)
375 declare i8* @llvm.coro.free(token, i8*)
376 declare i1 @llvm.coro.end(i8*, i1)
378 declare i8* @llvm.coro.subfn.addr(i8*, i8)
380 declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1)