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(
10 ; CHECK-NEXT: call void @print(i32 %n)
11 ; CHECK-NEXT: ret void
13 define void @no_suspends(i32 %n) "coroutine.presplit"="1" {
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
19 %size = call i32 @llvm.coro.size.i32()
20 %alloc = call i8* @malloc(i32 %size)
23 %phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ]
24 %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %phi)
27 call void @print(i32 %n)
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
34 call void @free(i8* %mem)
37 call i1 @llvm.coro.end(i8* %hdl, i1 false)
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
45 ; CHECK-LABEL: define void @simplify_resume(
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" {
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
59 %size = call i32 @llvm.coro.size.i32()
60 %alloc = call i8* @malloc(i32 %size)
63 %phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ]
64 %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %phi)
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]
77 call void @print(i32 0)
81 call void @print(i32 1)
85 %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
86 call void @free(i8* %mem)
89 call i1 @llvm.coro.end(i8* %hdl, i1 false)
93 ; SimplifySuspendPoint will detect that coroutine destroys itself and will
94 ; replace suspend with a jump to %cleanup label turning it into no-suspend
97 ; CHECK-LABEL: define void @simplify_destroy(
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 {
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
110 %size = call i32 @llvm.coro.size.i32()
111 %alloc = call i8* @malloc(i32 %size)
114 %phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ]
115 %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %phi)
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
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]
128 call void @print(i32 0)
132 call void @print(i32 1)
136 %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
137 call void @free(i8* %mem)
140 call i1 @llvm.coro.end(i8* %hdl, i1 false)
143 %lpval = landingpad { i8*, i32 }
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
154 ; CHECK-LABEL: define void @simplify_resume_with_inlined_if(
157 ; CHECK-NEXT: bitcast
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" {
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
168 %size = call i32 @llvm.coro.size.i32()
169 %alloc = call i8* @malloc(i32 %size)
172 %phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ]
173 %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %phi)
176 %save = call token @llvm.coro.save(i8* %hdl)
177 br i1 %cond, label %if.then, label %if.else
179 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 1, i1 false)
182 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %src, i8* %dst, i64 1, i1 false)
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]
192 call void @print(i32 0)
196 call void @print(i32 1)
200 %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
201 call void @free(i8* %mem)
204 call i1 @llvm.coro.end(i8* %hdl, i1 false)
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(
216 ; CHECK-NEXT: llvm.coro.id
218 define void @cannot_simplify_other_calls() "coroutine.presplit"="1" {
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
224 %size = call i32 @llvm.coro.size.i32()
225 %alloc = call i8* @malloc(i32 %size)
228 %phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ]
229 %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %phi)
232 %save = call token @llvm.coro.save(i8* %hdl)
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]
247 call void @print(i32 0)
251 call void @print(i32 1)
255 %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
256 call void @free(i8* %mem)
259 call i1 @llvm.coro.end(i8* %hdl, i1 false)
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(
269 ; CHECK-NEXT: llvm.coro.id
271 define void @cannot_simplify_calls_in_terminator() "coroutine.presplit"="1" personality i32 0 {
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
277 %size = call i32 @llvm.coro.size.i32()
278 %alloc = call i8* @malloc(i32 %size)
281 %phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ]
282 %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %phi)
285 %save = call token @llvm.coro.save(i8* %hdl)
286 invoke void @foo() to label %resume_cont unwind label %lpad
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]
295 call void @print(i32 0)
299 call void @print(i32 1)
303 %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
304 call void @free(i8* %mem)
307 call i1 @llvm.coro.end(i8* %hdl, i1 false)
310 %lpval = landingpad { i8*, i32 }
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(
322 ; CHECK-NEXT: llvm.coro.id
324 define void @cannot_simplify_not_last_instr(i8* %dst, i8* %src) "coroutine.presplit"="1" {
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
330 %size = call i32 @llvm.coro.size.i32()
331 %alloc = call i8* @malloc(i32 %size)
334 %phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ]
335 %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %phi)
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]
348 call void @print(i32 0)
352 call void @print(i32 1)
356 %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
357 call void @free(i8* %mem)
360 call i1 @llvm.coro.end(i8* %hdl, i1 false)
364 declare i8* @malloc(i32)
365 declare void @free(i8*)
366 declare void @print(i32)
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)