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(
8 ; CHECK-NEXT: call void @print(i32 %n)
11 define void @no_suspends(i32 %n) presplitcoroutine {
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
17 %size = call i32 @llvm.coro.size.i32()
18 %alloc = call ptr @malloc(i32 %size)
21 %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
22 %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)
25 call void @print(i32 %n)
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
32 call void @free(ptr %mem)
35 call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
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
43 ; CHECK-LABEL: define void @simplify_resume(
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 {
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
55 %size = call i32 @llvm.coro.size.i32()
56 %alloc = call ptr @malloc(i32 %size)
59 %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
60 %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)
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]
72 call void @print(i32 0)
76 call void @print(i32 1)
80 %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)
81 call void @free(ptr %mem)
84 call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
88 ; SimplifySuspendPoint will detect that coroutine destroys itself and will
89 ; replace suspend with a jump to %cleanup label turning it into no-suspend
92 ; CHECK-LABEL: define void @simplify_destroy(
94 ; CHECK-NEXT: call void @print(i32 1)
95 ; CHECK-NEXT: ret void
97 define void @simplify_destroy() presplitcoroutine personality i32 0 {
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
103 %size = call i32 @llvm.coro.size.i32()
104 %alloc = call ptr @malloc(i32 %size)
107 %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
108 %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)
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
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]
120 call void @print(i32 0)
124 call void @print(i32 1)
128 %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)
129 call void @free(ptr %mem)
132 call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
135 %lpval = landingpad { ptr, i32 }
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
146 ; CHECK-LABEL: define void @simplify_resume_with_inlined_if(
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 {
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
158 %size = call i32 @llvm.coro.size.i32()
159 %alloc = call ptr @malloc(i32 %size)
162 %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
163 %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)
166 %save = call token @llvm.coro.save(ptr %hdl)
167 br i1 %cond, label %if.then, label %if.else
169 call void @llvm.memcpy.p0.p0.i64(ptr %dst, ptr %src, i64 1, i1 false)
172 call void @llvm.memcpy.p0.p0.i64(ptr %src, ptr %dst, i64 1, i1 false)
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]
181 call void @print(i32 0)
185 call void @print(i32 1)
189 %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)
190 call void @free(ptr %mem)
193 call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
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(
205 ; CHECK-NEXT: llvm.coro.id
207 define void @cannot_simplify_other_calls() presplitcoroutine {
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
213 %size = call i32 @llvm.coro.size.i32()
214 %alloc = call ptr @malloc(i32 %size)
217 %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
218 %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)
221 %save = call token @llvm.coro.save(ptr %hdl)
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]
235 call void @print(i32 0)
239 call void @print(i32 1)
243 %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)
244 call void @free(ptr %mem)
247 call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
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(
257 ; CHECK-NEXT: llvm.coro.id
259 define void @cannot_simplify_calls_in_terminator() presplitcoroutine personality i32 0 {
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
265 %size = call i32 @llvm.coro.size.i32()
266 %alloc = call ptr @malloc(i32 %size)
269 %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
270 %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)
273 %save = call token @llvm.coro.save(ptr %hdl)
274 invoke void @foo() to label %resume_cont unwind label %lpad
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]
282 call void @print(i32 0)
286 call void @print(i32 1)
290 %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)
291 call void @free(ptr %mem)
294 call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
297 %lpval = landingpad { ptr, i32 }
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(
309 ; CHECK-NEXT: llvm.coro.id
311 define void @cannot_simplify_not_last_instr(ptr %dst, ptr %src) presplitcoroutine {
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
317 %size = call i32 @llvm.coro.size.i32()
318 %alloc = call ptr @malloc(i32 %size)
321 %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
322 %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)
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]
334 call void @print(i32 0)
338 call void @print(i32 1)
342 %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)
343 call void @free(ptr %mem)
346 call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
350 ; SimplifySuspendPoint should not simplify final suspend point
352 ; CHECK-LABEL: define void @cannot_simplify_final_suspend(
354 ; CHECK-NEXT: llvm.coro.id
356 define void @cannot_simplify_final_suspend() presplitcoroutine personality i32 0 {
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
362 %size = call i32 @llvm.coro.size.i32()
363 %alloc = call ptr @malloc(i32 %size)
366 %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ]
367 %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi)
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
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]
379 call void @print(i32 0)
383 call void @print(i32 1)
387 %mem = call ptr @llvm.coro.free(token %id, ptr %hdl)
388 call void @free(ptr %mem)
391 call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
394 %lpval = landingpad { ptr, i32 }
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)
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)