[InstCombine] Signed saturation tests. NFC
[llvm-complete.git] / test / Transforms / Coroutines / coro-heap-elide.ll
blob5ce2b693bc5e5d28f3d2fd60cc50a46ffb61d537
1 ; Tests that the dynamic allocation and deallocation of the coroutine frame is
2 ; elided and any tail calls referencing the coroutine frame has the tail 
3 ; call attribute removed.
4 ; RUN: opt < %s -S -inline -coro-elide -instsimplify -simplifycfg | FileCheck %s
6 declare void @print(i32) nounwind
8 %f.frame = type {i32}
10 declare void @bar(i8*)
12 declare fastcc void @f.resume(%f.frame*)
13 declare fastcc void @f.destroy(%f.frame*)
14 declare fastcc void @f.cleanup(%f.frame*)
16 declare void @may_throw()
17 declare i8* @CustomAlloc(i32)
18 declare void @CustomFree(i8*)
20 @f.resumers = internal constant [3 x void (%f.frame*)*] 
21   [void (%f.frame*)* @f.resume, void (%f.frame*)* @f.destroy, void (%f.frame*)* @f.cleanup]
23 ; a coroutine start function
24 define i8* @f() personality i8* null {
25 entry:
26   %id = call token @llvm.coro.id(i32 0, i8* null,
27                       i8* bitcast (i8*()* @f to i8*),
28                       i8* bitcast ([3 x void (%f.frame*)*]* @f.resumers to i8*))
29   %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id)
30   br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin
31 dyn.alloc:
32   %alloc = call i8* @CustomAlloc(i32 4)
33   br label %coro.begin
34 coro.begin:
35   %phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ]
36   %hdl = call i8* @llvm.coro.begin(token %id, i8* %phi)
37   invoke void @may_throw() 
38     to label %ret unwind label %ehcleanup
39 ret:          
40   ret i8* %hdl
42 ehcleanup:
43   %tok = cleanuppad within none []
44   %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
45   %need.dyn.free = icmp ne i8* %mem, null
46   br i1 %need.dyn.free, label %dyn.free, label %if.end
47 dyn.free:
48   call void @CustomFree(i8* %mem)
49   br label %if.end
50 if.end:
51   cleanupret from %tok unwind to caller
54 ; CHECK-LABEL: @callResume(
55 define void @callResume() {
56 entry:
57 ; CHECK: alloca %f.frame
58 ; CHECK-NOT: coro.begin
59 ; CHECK-NOT: CustomAlloc
60 ; CHECK: call void @may_throw()
61   %hdl = call i8* @f()
63 ; Need to remove 'tail' from the first call to @bar
64 ; CHECK-NOT: tail call void @bar(
65 ; CHECK: call void @bar(
66   tail call void @bar(i8* %hdl)
67 ; CHECK: tail call void @bar(
68   tail call void @bar(i8* null)
70 ; CHECK-NEXT: call fastcc void bitcast (void (%f.frame*)* @f.resume to void (i8*)*)(i8* %vFrame)
71   %0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0)
72   %1 = bitcast i8* %0 to void (i8*)*
73   call fastcc void %1(i8* %hdl)
75 ; CHECK-NEXT: call fastcc void bitcast (void (%f.frame*)* @f.cleanup to void (i8*)*)(i8* %vFrame)
76   %2 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1)
77   %3 = bitcast i8* %2 to void (i8*)*
78   call fastcc void %3(i8* %hdl)
80 ; CHECK-NEXT: ret void
81   ret void
84 ; CHECK-LABEL: @callResume_PR34897_no_elision(
85 define void @callResume_PR34897_no_elision(i1 %cond) {
86 ; CHECK-LABEL: entry:
87 entry:
88 ; CHECK: call i8* @CustomAlloc(
89   %hdl = call i8* @f()
90 ; CHECK: tail call void @bar(
91   tail call void @bar(i8* %hdl)
92 ; CHECK: tail call void @bar(
93   tail call void @bar(i8* null)
94   br i1 %cond, label %if.then, label %if.else
96 ; CHECK-LABEL: if.then:
97 if.then:
98 ; CHECK: call fastcc void bitcast (void (%f.frame*)* @f.resume to void (i8*)*)(i8*
99   %0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0)
100   %1 = bitcast i8* %0 to void (i8*)*
101   call fastcc void %1(i8* %hdl)
102 ; CHECK-NEXT: call fastcc void bitcast (void (%f.frame*)* @f.destroy to void (i8*)*)(i8*
103   %2 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1)
104   %3 = bitcast i8* %2 to void (i8*)*
105   call fastcc void %3(i8* %hdl)
106   br label %return
108 if.else:
109   br label %return
111 ; CHECK-LABEL: return:
112 return:
113 ; CHECK: ret void
114   ret void
117 ; a coroutine start function (cannot elide heap alloc, due to second argument to
118 ; coro.begin not pointint to coro.alloc)
119 define i8* @f_no_elision() personality i8* null {
120 entry:
121   %id = call token @llvm.coro.id(i32 0, i8* null,
122                       i8* bitcast (i8*()* @f_no_elision to i8*),
123                       i8* bitcast ([3 x void (%f.frame*)*]* @f.resumers to i8*))
124   %alloc = call i8* @CustomAlloc(i32 4)
125   %hdl = call i8* @llvm.coro.begin(token %id, i8* %alloc)
126   ret i8* %hdl
129 ; CHECK-LABEL: @callResume_no_elision(
130 define void @callResume_no_elision() {
131 entry:
132 ; CHECK: call i8* @CustomAlloc(
133   %hdl = call i8* @f_no_elision()
135 ; Tail call should remain tail calls
136 ; CHECK: tail call void @bar(
137   tail call void @bar(i8* %hdl)
138 ; CHECK: tail call void @bar(  
139   tail call void @bar(i8* null)
141 ; CHECK-NEXT: call fastcc void bitcast (void (%f.frame*)* @f.resume to void (i8*)*)(i8*
142   %0 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 0)
143   %1 = bitcast i8* %0 to void (i8*)*
144   call fastcc void %1(i8* %hdl)
146 ; CHECK-NEXT: call fastcc void bitcast (void (%f.frame*)* @f.destroy to void (i8*)*)(i8*
147   %2 = call i8* @llvm.coro.subfn.addr(i8* %hdl, i8 1)
148   %3 = bitcast i8* %2 to void (i8*)*
149   call fastcc void %3(i8* %hdl)
151 ; CHECK-NEXT: ret void
152   ret void
155 declare token @llvm.coro.id(i32, i8*, i8*, i8*)
156 declare i1 @llvm.coro.alloc(token)
157 declare i8* @llvm.coro.free(token, i8*)
158 declare i8* @llvm.coro.begin(token, i8*)
159 declare i8* @llvm.coro.frame(token)
160 declare i8* @llvm.coro.subfn.addr(i8*, i8)