xref: /llvm-project/llvm/test/Transforms/Coroutines/coro-alloca-08.ll (revision 51d5d7bbae92493a5bfa7cc6b519de8a5bb32fdb)
1; RUN: opt < %s -passes='cgscc(coro-split),simplifycfg,early-cse' -S | FileCheck %s
2
3%"struct.std::coroutine_handle" = type { ptr }
4%"struct.std::coroutine_handle.0" = type { %"struct.std::coroutine_handle" }
5%"struct.lean_future<int>::Awaiter" = type { i32, %"struct.std::coroutine_handle.0" }
6
7declare ptr @malloc(i64)
8
9%i8.array = type { [100 x i8] }
10declare void @consume.i8.array(ptr)
11
12; The lifetime of testval starts and ends before coro.suspend. Even though consume.i8.array
13; might capture it, we can safely say it won't live across suspension.
14define void @foo() presplitcoroutine {
15entry:
16  %testval = alloca %i8.array
17  %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
18  %alloc = call ptr @malloc(i64 16) #3
19  %vFrame = call noalias nonnull ptr @llvm.coro.begin(token %id, ptr %alloc)
20
21  call void @llvm.lifetime.start.p0(i64 100, ptr %testval)
22  call void @consume.i8.array(ptr %testval)
23  call void @llvm.lifetime.end.p0(i64 100, ptr  %testval)
24
25  %save = call token @llvm.coro.save(ptr null)
26  %suspend = call i8 @llvm.coro.suspend(token %save, i1 false)
27  switch i8 %suspend, label %exit [
28    i8 0, label %await.ready
29    i8 1, label %exit
30  ]
31await.ready:
32  %StrayCoroSave = call token @llvm.coro.save(ptr null)
33  br label %exit
34exit:
35  call i1 @llvm.coro.end(ptr null, i1 false, token none)
36  ret void
37}
38
39; The lifetime of testval starts after coro.suspend. So it will never live across suspension
40; points.
41define void @bar() presplitcoroutine {
42entry:
43  %testval = alloca %i8.array
44  %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
45  %alloc = call ptr @malloc(i64 16) #3
46  %vFrame = call noalias nonnull ptr @llvm.coro.begin(token %id, ptr %alloc)
47  %save = call token @llvm.coro.save(ptr null)
48  %suspend = call i8 @llvm.coro.suspend(token %save, i1 false)
49  switch i8 %suspend, label %exit [
50    i8 0, label %await.ready
51    i8 1, label %exit
52  ]
53await.ready:
54  %StrayCoroSave = call token @llvm.coro.save(ptr null)
55
56  call void @llvm.lifetime.start.p0(i64 100, ptr %testval)
57  call void @consume.i8.array(ptr %testval)
58  call void @llvm.lifetime.end.p0(i64 100, ptr  %testval)
59
60  br label %exit
61exit:
62  call i1 @llvm.coro.end(ptr null, i1 false, token none)
63  ret void
64}
65
66; Verify that for both foo and bar, testval isn't put on the frame.
67; CHECK: %foo.Frame = type { ptr, ptr, i1 }
68; CHECK: %bar.Frame = type { ptr, ptr, i1 }
69
70declare token @llvm.coro.id(i32, ptr readnone, ptr nocapture readonly, ptr)
71declare i1 @llvm.coro.alloc(token) #3
72declare i64 @llvm.coro.size.i64() #5
73declare ptr @llvm.coro.begin(token, ptr writeonly) #3
74declare token @llvm.coro.save(ptr) #3
75declare ptr @llvm.coro.frame() #5
76declare i8 @llvm.coro.suspend(token, i1) #3
77declare ptr @llvm.coro.free(token, ptr nocapture readonly) #2
78declare i1 @llvm.coro.end(ptr, i1, token) #3
79declare void @llvm.lifetime.start.p0(i64, ptr nocapture) #4
80declare void @llvm.lifetime.end.p0(i64, ptr nocapture) #4
81