[DAGCombiner] Add target hook function to decide folding (mul (add x, c1), c2)
[llvm-project.git] / llvm / test / Transforms / Coroutines / coro-retcon-alloca.ll
blobbf2862fcac2bd80c8c56a392598247cdf1e0fef9
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -enable-coroutines -passes='default<O2>' -S | FileCheck %s
4 target datalayout = "p:64:64:64"
6 declare {i8*, i8*, i32} @prototype_f(i8*, i1)
7 define {i8*, i8*, i32} @f(i8* %buffer, i32 %n) {
8 ; CHECK-LABEL: @f(
9 ; CHECK-NEXT:  coro.return:
10 ; CHECK-NEXT:    [[N_VAL_SPILL_ADDR:%.*]] = getelementptr inbounds i8, i8* [[BUFFER:%.*]], i64 8
11 ; CHECK-NEXT:    [[TMP0:%.*]] = bitcast i8* [[N_VAL_SPILL_ADDR]] to i32*
12 ; CHECK-NEXT:    store i32 [[N:%.*]], i32* [[TMP0]], align 4
13 ; CHECK-NEXT:    [[TMP1:%.*]] = tail call i8* @allocate(i32 [[N]]) #[[ATTR0:[0-9]+]]
14 ; CHECK-NEXT:    [[DOTSPILL_ADDR:%.*]] = bitcast i8* [[BUFFER]] to i8**
15 ; CHECK-NEXT:    store i8* [[TMP1]], i8** [[DOTSPILL_ADDR]], align 8
16 ; CHECK-NEXT:    [[TMP2:%.*]] = insertvalue { i8*, i8*, i32 } { i8* bitcast ({ i8*, i8*, i32 } (i8*, i1)* @f.resume.0 to i8*), i8* undef, i32 undef }, i8* [[TMP1]], 1
17 ; CHECK-NEXT:    [[TMP3:%.*]] = insertvalue { i8*, i8*, i32 } [[TMP2]], i32 [[N]], 2
18 ; CHECK-NEXT:    ret { i8*, i8*, i32 } [[TMP3]]
20 entry:
21   %id = call token @llvm.coro.id.retcon(i32 1024, i32 8, i8* %buffer, i8* bitcast ({i8*, i8*, i32} (i8*, i1)* @prototype_f to i8*), i8* bitcast (i8* (i32)* @allocate to i8*), i8* bitcast (void (i8*)* @deallocate to i8*))
22   %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
23   br label %loop
25 loop:
26   %n.val = phi i32 [ %n, %entry ], [ %inc, %resume ]
27   %alloca = call token @llvm.coro.alloca.alloc.i32(i32 %n.val, i32 8)
28   %ptr = call i8* @llvm.coro.alloca.get(token %alloca)
29   %unwind = call i1 (...) @llvm.coro.suspend.retcon.i1(i8* %ptr, i32 %n.val)
30   call void @llvm.coro.alloca.free(token %alloca)
31   br i1 %unwind, label %cleanup, label %resume
33 resume:
34   %inc = add i32 %n.val, 1
35   br label %loop
37 cleanup:
38   call i1 @llvm.coro.end(i8* %hdl, i1 0)
39   unreachable
44 declare {i8*, i32} @prototype_g(i8*, i1)
45 define {i8*, i32} @g(i8* %buffer, i32 %n) {
46 ; CHECK-LABEL: @g(
47 ; CHECK-NEXT:  coro.return:
48 ; CHECK-NEXT:    [[N_VAL_SPILL_ADDR:%.*]] = bitcast i8* [[BUFFER:%.*]] to i32*
49 ; CHECK-NEXT:    store i32 [[N:%.*]], i32* [[N_VAL_SPILL_ADDR]], align 4
50 ; CHECK-NEXT:    [[TMP0:%.*]] = zext i32 [[N]] to i64
51 ; CHECK-NEXT:    [[TMP1:%.*]] = alloca i8, i64 [[TMP0]], align 8
52 ; CHECK-NEXT:    tail call void @use(i8* nonnull [[TMP1]])
53 ; CHECK-NEXT:    [[TMP2:%.*]] = insertvalue { i8*, i32 } { i8* bitcast ({ i8*, i32 } (i8*, i1)* @g.resume.0 to i8*), i32 undef }, i32 [[N]], 1
54 ; CHECK-NEXT:    ret { i8*, i32 } [[TMP2]]
56 entry:
57   %id = call token @llvm.coro.id.retcon(i32 1024, i32 8, i8* %buffer, i8* bitcast ({i8*, i32} (i8*, i1)* @prototype_g to i8*), i8* bitcast (i8* (i32)* @allocate to i8*), i8* bitcast (void (i8*)* @deallocate to i8*))
58   %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
59   br label %loop
61 loop:
62   %n.val = phi i32 [ %n, %entry ], [ %inc, %resume ]
63   %alloca = call token @llvm.coro.alloca.alloc.i32(i32 %n.val, i32 8)
64   %ptr = call i8* @llvm.coro.alloca.get(token %alloca)
65   call void @use(i8* %ptr)
66   call void @llvm.coro.alloca.free(token %alloca)
67   %unwind = call i1 (...) @llvm.coro.suspend.retcon.i1(i32 %n.val)
68   br i1 %unwind, label %cleanup, label %resume
70 resume:
71   %inc = add i32 %n.val, 1
72   br label %loop
74 cleanup:
75   call i1 @llvm.coro.end(i8* %hdl, i1 0)
76   unreachable
81 declare {i8*, i32} @prototype_h(i8*, i1)
82 define {i8*, i32} @h(i8* %buffer, i32 %n) {
83 ; CHECK-LABEL: @h(
84 ; CHECK-NEXT:  coro.return:
85 ; CHECK-NEXT:    [[N_SPILL_ADDR:%.*]] = bitcast i8* [[BUFFER:%.*]] to i32*
86 ; CHECK-NEXT:    store i32 [[N:%.*]], i32* [[N_SPILL_ADDR]], align 4
87 ; CHECK-NEXT:    [[TMP0:%.*]] = insertvalue { i8*, i32 } { i8* bitcast ({ i8*, i32 } (i8*, i1)* @h.resume.0 to i8*), i32 undef }, i32 [[N]], 1
88 ; CHECK-NEXT:    ret { i8*, i32 } [[TMP0]]
90 entry:
91   %id = call token @llvm.coro.id.retcon(i32 1024, i32 8, i8* %buffer, i8* bitcast ({i8*, i32} (i8*, i1)* @prototype_h to i8*), i8* bitcast (i8* (i32)* @allocate to i8*), i8* bitcast (void (i8*)* @deallocate to i8*))
92   %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
93   br label %loop
95 loop:
96   %n.val = phi i32 [ %n, %entry ], [ %inc, %resume ]
97   %unwind = call i1 (...) @llvm.coro.suspend.retcon.i1(i32 %n.val)
98   br i1 %unwind, label %cleanup, label %resume
100 resume:
101   %inc = add i32 %n.val, 1
102   %alloca = call token @llvm.coro.alloca.alloc.i32(i32 %inc, i32 8)
103   %ptr = call i8* @llvm.coro.alloca.get(token %alloca)
104   call void @use(i8* %ptr)
105   call void @llvm.coro.alloca.free(token %alloca)
106   br label %loop
108 cleanup:
109   call i1 @llvm.coro.end(i8* %hdl, i1 0)
110   unreachable
115 declare {i8*, i32} @prototype_i(i8*)
116 define {i8*, i32} @i(i8* %buffer, i32 %n) {
117 ; CHECK-LABEL: @i(
118 ; CHECK-NEXT:  coro.return:
119 ; CHECK-NEXT:    [[N_VAL_SPILL_ADDR:%.*]] = bitcast i8* [[BUFFER:%.*]] to i32*
120 ; CHECK-NEXT:    store i32 [[N:%.*]], i32* [[N_VAL_SPILL_ADDR]], align 4
121 ; CHECK-NEXT:    [[TMP0:%.*]] = insertvalue { i8*, i32 } { i8* bitcast ({ i8*, i32 } (i8*)* @i.resume.0 to i8*), i32 undef }, i32 [[N]], 1
122 ; CHECK-NEXT:    ret { i8*, i32 } [[TMP0]]
124 entry:
125   %id = call token @llvm.coro.id.retcon(i32 1024, i32 8, i8* %buffer, i8* bitcast ({i8*, i32} (i8*)* @prototype_i to i8*), i8* bitcast (i8* (i32)* @allocate to i8*), i8* bitcast (void (i8*)* @deallocate to i8*))
126   %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
127   br label %loop
129 loop:
130   %n.val = phi i32 [ %n, %entry ], [ %k, %loop2 ]
131   call void (...) @llvm.coro.suspend.retcon.isVoid(i32 %n.val)
132   %inc = add i32 %n.val, 1
133   br label %loop2
135 loop2:
136   %k = phi i32 [ %inc, %loop ], [ %k2, %loop2 ]
137   %alloca = call token @llvm.coro.alloca.alloc.i32(i32 %k, i32 8)
138   %ptr = call i8* @llvm.coro.alloca.get(token %alloca)
139   call void @use(i8* %ptr)
140   call void @llvm.coro.alloca.free(token %alloca)
141   %k2 = lshr i32 %k, 1
142   %cmp = icmp ugt i32 %k, 128
143   br i1 %cmp, label %loop2, label %loop
148 declare {i8*, i32} @prototype_j(i8*)
149 define {i8*, i32} @j(i8* %buffer, i32 %n) {
150 ; CHECK-LABEL: @j(
151 ; CHECK-NEXT:  coro.return:
152 ; CHECK-NEXT:    [[N_VAL_SPILL_ADDR:%.*]] = bitcast i8* [[BUFFER:%.*]] to i32*
153 ; CHECK-NEXT:    store i32 [[N:%.*]], i32* [[N_VAL_SPILL_ADDR]], align 4
154 ; CHECK-NEXT:    [[TMP0:%.*]] = insertvalue { i8*, i32 } { i8* bitcast ({ i8*, i32 } (i8*)* @j.resume.0 to i8*), i32 undef }, i32 [[N]], 1
155 ; CHECK-NEXT:    ret { i8*, i32 } [[TMP0]]
157 entry:
158   %id = call token @llvm.coro.id.retcon(i32 1024, i32 8, i8* %buffer, i8* bitcast ({i8*, i32} (i8*)* @prototype_j to i8*), i8* bitcast (i8* (i32)* @allocate to i8*), i8* bitcast (void (i8*)* @deallocate to i8*))
159   %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
160   br label %forward
162 back:
163   ; We should encounter this 'get' before we encounter the 'alloc'.
164   %ptr = call i8* @llvm.coro.alloca.get(token %alloca)
165   call void @use(i8* %ptr)
166   call void @llvm.coro.alloca.free(token %alloca)
167   %k = add i32 %n.val, 1
168   %cmp = icmp ugt i32 %k, 128
169   br i1 %cmp, label %forward, label %end
171 forward:
172   %n.val = phi i32 [ %n, %entry ], [ %k, %back ]
173   call void (...) @llvm.coro.suspend.retcon.isVoid(i32 %n.val)
174   %alloca = call token @llvm.coro.alloca.alloc.i32(i32 %n.val, i32 8)
175   %inc = add i32 %n.val, 1
176   br label %back
178 end:
179   call i1 @llvm.coro.end(i8* %hdl, i1 0)
180   unreachable
183 declare i32 @getSize()
184 define {i8*, i32} @k(i8* %buffer, i32 %n, i1 %cond) {
185 ; CHECK-LABEL: @k(
186 ; CHECK-NEXT:  PostSpill:
187 ; CHECK-NEXT:    [[SIZE:%.*]] = tail call i32 @getSize()
188 ; CHECK-NEXT:    br i1 [[COND:%.*]], label [[ALLOCA_BLOCK:%.*]], label [[CORO_RETURN:%.*]]
189 ; CHECK:       coro.return:
190 ; CHECK-NEXT:    [[TMP0:%.*]] = insertvalue { i8*, i32 } { i8* bitcast ({ i8*, i32 } (i8*, i1)* @k.resume.0 to i8*), i32 undef }, i32 [[N:%.*]], 1
191 ; CHECK-NEXT:    ret { i8*, i32 } [[TMP0]]
192 ; CHECK:       alloca_block:
193 ; CHECK-NEXT:    [[TMP1:%.*]] = zext i32 [[SIZE]] to i64
194 ; CHECK-NEXT:    [[TMP2:%.*]] = alloca i8, i64 [[TMP1]], align 8
195 ; CHECK-NEXT:    tail call void @use(i8* nonnull [[TMP2]])
196 ; CHECK-NEXT:    br label [[CORO_RETURN]]
198 entry:
199   %id = call token @llvm.coro.id.retcon(i32 1024, i32 8, i8* %buffer, i8* bitcast ({i8*, i32} (i8*, i1)* @prototype_g to i8*), i8* bitcast (i8* (i32)* @allocate to i8*), i8* bitcast (void (i8*)* @deallocate to i8*))
200   %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
201   br i1 %cond, label %alloca_block, label %non_alloca_block
203 suspend:
204   %unwind = call i1 (...) @llvm.coro.suspend.retcon.i1(i32 %n)
205   br i1 %unwind, label %cleanup, label %resume
207 resume:
208   br label %cleanup
210 alloca_block:
211   %size = call i32 @getSize()
212   ; This will get lowered to a dynamic alloca.
213   ; Make sure code that runs after that lowering does not hoist the dynamic
214   ; alloca into the entry block of the resume function.
215   %alloca = call token @llvm.coro.alloca.alloc.i32(i32 %size, i32 8)
216   %ptr = call i8* @llvm.coro.alloca.get(token %alloca)
217   call void @use(i8* %ptr)
218   call void @llvm.coro.alloca.free(token %alloca)
219   br label %suspend
221 non_alloca_block:
222   %ignore = call i32 @getSize()
223   br label %suspend
225 cleanup:
226   call i1 @llvm.coro.end(i8* %hdl, i1 0)
227   unreachable
230 declare token @llvm.coro.id.retcon(i32, i32, i8*, i8*, i8*, i8*)
231 declare i8* @llvm.coro.begin(token, i8*)
232 declare i1 @llvm.coro.suspend.retcon.i1(...)
233 declare void @llvm.coro.suspend.retcon.isVoid(...)
234 declare i1 @llvm.coro.end(i8*, i1)
235 declare i8* @llvm.coro.prepare.retcon(i8*)
236 declare token @llvm.coro.alloca.alloc.i32(i32, i32)
237 declare i8* @llvm.coro.alloca.get(token)
238 declare void @llvm.coro.alloca.free(token)
240 declare noalias i8* @allocate(i32 %size)
241 declare void @deallocate(i8* %ptr)
243 declare void @print(i32)
244 declare void @use(i8*)