xref: /llvm-project/clang/test/CodeGenCoroutines/coro-await.cpp (revision 94473f4db6a6f5f12d7c4081455b5b596094eac5)
1 // RUN: %clang_cc1 -no-enable-noundef-analysis -triple x86_64-unknown-linux-gnu -std=c++20 \
2 // RUN:   -emit-llvm %s -o - -disable-llvm-passes -Wno-coroutine -Wno-unused | FileCheck %s
3 
4 namespace std {
5 template <typename... T>
6 struct coroutine_traits;
7 
8 template <typename Promise = void> struct coroutine_handle;
9 
10 template <>
11 struct coroutine_handle<void> {
12   void *ptr;
13   static coroutine_handle from_address(void *);
14   void *address();
15 };
16 
17 template <typename Promise>
18 struct coroutine_handle : coroutine_handle<> {
19   static coroutine_handle from_address(void *) noexcept;
20 };
21 
22 } // namespace std
23 
24 struct init_susp {
25   bool await_ready();
26   void await_suspend(std::coroutine_handle<>);
27   void await_resume();
28 };
29 struct final_susp {
30   bool await_ready() noexcept;
31   void await_suspend(std::coroutine_handle<>) noexcept;
32   void await_resume() noexcept;
33 };
34 
35 struct suspend_always {
36   int stuff;
37   bool await_ready();
38   void await_suspend(std::coroutine_handle<>);
39   void await_resume();
40 };
41 
42 template <>
43 struct std::coroutine_traits<void> {
44   struct promise_type {
45     void get_return_object();
46     init_susp initial_suspend();
47     final_susp final_suspend() noexcept;
48     void return_void();
49   };
50 };
51 
52 // CHECK-LABEL: f0(
53 extern "C" void f0() {
54   // CHECK: %[[FRAME:.+]] = call ptr @llvm.coro.begin(
55 
56   // See if initial_suspend was issued:
57   // ----------------------------------
58   // CHECK: call void @_ZNSt16coroutine_traitsIJvEE12promise_type15initial_suspendEv(
59   // CHECK-NEXT: call zeroext i1 @_ZN9init_susp11await_readyEv(ptr
60   // CHECK: %[[INITSP_ID:.+]] = call token @llvm.coro.save(
61   // CHECK: call i8 @llvm.coro.suspend(token %[[INITSP_ID]], i1 false)
62 
63   co_await suspend_always{};
64   // See if we need to suspend:
65   // --------------------------
66   // CHECK: %[[READY:.+]] = call zeroext i1 @_ZN14suspend_always11await_readyEv(ptr {{[^,]*}} %[[AWAITABLE:.+]])
67   // CHECK: br i1 %[[READY]], label %[[READY_BB:.+]], label %[[SUSPEND_BB:.+]]
68 
69   // If we are suspending:
70   // ---------------------
71   // CHECK: [[SUSPEND_BB]]:
72   // CHECK: %[[SUSPEND_ID:.+]] = call token @llvm.coro.save(
73   // ---------------------------
74   // Call coro.await.suspend
75   // ---------------------------
76   // CHECK-NEXT: call void @llvm.coro.await.suspend.void(ptr %[[AWAITABLE]], ptr %[[FRAME]], ptr @f0.__await_suspend_wrapper__await)
77   // -------------------------
78   // Generate a suspend point:
79   // -------------------------
80   // CHECK-NEXT: %[[OUTCOME:.+]] = call i8 @llvm.coro.suspend(token %[[SUSPEND_ID]], i1 false)
81   // CHECK: switch i8 %[[OUTCOME]], label %[[RET_BB:.+]] [
82   // CHECK:   i8 0, label %[[READY_BB]]
83   // CHECK:   i8 1, label %[[CLEANUP_BB:.+]]
84   // CHECK: ]
85 
86   // Cleanup code goes here:
87   // -----------------------
88   // CHECK: [[CLEANUP_BB]]:
89 
90   // When coroutine is resumed, call await_resume
91   // --------------------------
92   // CHECK: [[READY_BB]]:
93   // CHECK:  call void @_ZN14suspend_always12await_resumeEv(ptr {{[^,]*}} %[[AWAITABLE]])
94 
95   // See if final_suspend was issued:
96   // ----------------------------------
97   // CHECK: call void @_ZNSt16coroutine_traitsIJvEE12promise_type13final_suspendEv(
98   // CHECK-NEXT: call zeroext i1 @_ZN10final_susp11await_readyEv(ptr
99   // CHECK: %[[FINALSP_ID:.+]] = call token @llvm.coro.save(
100   // CHECK: call i8 @llvm.coro.suspend(token %[[FINALSP_ID]], i1 true)
101 
102   // Await suspend wrapper
103   // CHECK: define{{.*}} @f0.__await_suspend_wrapper__await(ptr {{[^,]*}} %[[AWAITABLE_ARG:.+]], ptr {{[^,]*}} %[[FRAME_ARG:.+]])
104   // CHECK: store ptr %[[AWAITABLE_ARG]], ptr %[[AWAITABLE_TMP:.+]],
105   // CHECK: store ptr %[[FRAME_ARG]], ptr %[[FRAME_TMP:.+]],
106   // CHECK: %[[AWAITABLE:.+]] = load ptr, ptr %[[AWAITABLE_TMP]]
107   // CHECK: %[[FRAME:.+]] = load ptr, ptr %[[FRAME_TMP]]
108   // CHECK: call ptr @_ZNSt16coroutine_handleINSt16coroutine_traitsIJvEE12promise_typeEE12from_addressEPv(ptr %[[FRAME]])
109   //   ... many lines of code to coerce coroutine_handle into an ptr scalar
110   // CHECK: %[[CH:.+]] = load ptr, ptr %{{.+}}
111   // CHECK: call void @_ZN14suspend_always13await_suspendESt16coroutine_handleIvE(ptr {{[^,]*}} %[[AWAITABLE]], ptr %[[CH]])
112 }
113 
114 struct suspend_maybe {
115   float stuff;
116   ~suspend_maybe();
117   bool await_ready();
118   bool await_suspend(std::coroutine_handle<>);
119   void await_resume();
120 };
121 
122 template <>
123 struct std::coroutine_traits<void, int> {
124   struct promise_type {
125     void get_return_object();
126     init_susp initial_suspend();
127     final_susp final_suspend() noexcept;
128     void return_void();
129     suspend_maybe yield_value(int);
130   };
131 };
132 
133 // CHECK-LABEL: f1(
134 extern "C" void f1(int) {
135   // CHECK: %[[PROMISE:.+]] = alloca %"struct.std::coroutine_traits<void, int>::promise_type"
136   // CHECK: %[[FRAME:.+]] = call ptr @llvm.coro.begin(
137   co_yield 42;
138   // CHECK: call void @_ZNSt16coroutine_traitsIJviEE12promise_type11yield_valueEi(ptr dead_on_unwind writable sret(%struct.suspend_maybe) align 4 %[[AWAITER:.+]], ptr {{[^,]*}} %[[PROMISE]], i32 42)
139 
140   // See if we need to suspend:
141   // --------------------------
142   // CHECK: %[[READY:.+]] = call zeroext i1 @_ZN13suspend_maybe11await_readyEv(ptr {{[^,]*}} %[[AWAITABLE:.+]])
143   // CHECK: br i1 %[[READY]], label %[[READY_BB:.+]], label %[[SUSPEND_BB:.+]]
144 
145   // If we are suspending:
146   // ---------------------
147   // CHECK: [[SUSPEND_BB]]:
148   // CHECK: %[[SUSPEND_ID:.+]] = call token @llvm.coro.save(
149   // ---------------------------
150   // Call coro.await.suspend
151   // ---------------------------
152   // CHECK-NEXT: %[[YES:.+]] = call i1 @llvm.coro.await.suspend.bool(ptr %[[AWAITABLE]], ptr %[[FRAME]], ptr @f1.__await_suspend_wrapper__yield)
153   // -------------------------------------------
154   // See if await_suspend decided not to suspend
155   // -------------------------------------------
156   // CHECK: br i1 %[[YES]], label %[[SUSPEND_PLEASE:.+]], label %[[READY_BB]]
157 
158   // CHECK: [[SUSPEND_PLEASE]]:
159   // CHECK:    call i8 @llvm.coro.suspend(token %[[SUSPEND_ID]], i1 false)
160 
161   // CHECK: [[READY_BB]]:
162   // CHECK:     call void @_ZN13suspend_maybe12await_resumeEv(ptr {{[^,]*}} %[[AWAITABLE]])
163 
164   // Await suspend wrapper
165   // CHECK: define {{.*}} i1 @f1.__await_suspend_wrapper__yield(ptr {{[^,]*}} %[[AWAITABLE_ARG:.+]], ptr {{[^,]*}} %[[FRAME_ARG:.+]])
166   // CHECK: store ptr %[[AWAITABLE_ARG]], ptr %[[AWAITABLE_TMP:.+]],
167   // CHECK: store ptr %[[FRAME_ARG]], ptr %[[FRAME_TMP:.+]],
168   // CHECK: %[[AWAITABLE:.+]] = load ptr, ptr %[[AWAITABLE_TMP]]
169   // CHECK: %[[FRAME:.+]] = load ptr, ptr %[[FRAME_TMP]]
170   // CHECK: call ptr @_ZNSt16coroutine_handleINSt16coroutine_traitsIJviEE12promise_typeEE12from_addressEPv(ptr %[[FRAME]])
171   //   ... many lines of code to coerce coroutine_handle into an ptr scalar
172   // CHECK: %[[CH:.+]] = load ptr, ptr %{{.+}}
173   // CHECK: %[[YES:.+]] = call zeroext i1 @_ZN13suspend_maybe13await_suspendESt16coroutine_handleIvE(ptr {{[^,]*}} %[[AWAITABLE]], ptr %[[CH]])
174   // CHECK-NEXT: ret i1 %[[YES]]
175 }
176 
177 struct ComplexAwaiter {
178   template <typename F> void await_suspend(F);
179   bool await_ready();
180   _Complex float await_resume();
181 };
182 extern "C" void UseComplex(_Complex float);
183 
184 // CHECK-LABEL: @TestComplex(
185 extern "C" void TestComplex() {
186   UseComplex(co_await ComplexAwaiter{});
187   // CHECK: call <2 x float> @_ZN14ComplexAwaiter12await_resumeEv(ptr
188   // CHECK: call void @UseComplex(<2 x float> %{{.+}})
189 
190   co_await ComplexAwaiter{};
191   // CHECK: call <2 x float> @_ZN14ComplexAwaiter12await_resumeEv(ptr
192 
193   _Complex float Val = co_await ComplexAwaiter{};
194   // CHECK: call <2 x float> @_ZN14ComplexAwaiter12await_resumeEv(ptr
195 }
196 
197 struct Aggr { int X, Y, Z; ~Aggr(); };
198 struct AggrAwaiter {
199   template <typename F> void await_suspend(F);
200   bool await_ready();
201   Aggr await_resume();
202 };
203 
204 extern "C" void Whatever();
205 extern "C" void UseAggr(Aggr&&);
206 
207 // FIXME: Once the cleanup code is in, add testing that destructors for Aggr
208 // are invoked properly on the cleanup branches.
209 
210 // CHECK-LABEL: @TestAggr(
211 extern "C" void TestAggr() {
212   UseAggr(co_await AggrAwaiter{});
213   Whatever();
214   // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(ptr dead_on_unwind writable sret(%struct.Aggr) align 4 %[[AwaitResume:.+]],
215   // CHECK: call void @UseAggr(ptr nonnull align 4 dereferenceable(12) %[[AwaitResume]])
216   // CHECK: call void @_ZN4AggrD1Ev(ptr {{[^,]*}} %[[AwaitResume]])
217   // CHECK: call void @Whatever()
218 
219   co_await AggrAwaiter{};
220   Whatever();
221   // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(ptr dead_on_unwind writable sret(%struct.Aggr) align 4 %[[AwaitResume2:.+]],
222   // CHECK: call void @_ZN4AggrD1Ev(ptr {{[^,]*}} %[[AwaitResume2]])
223   // CHECK: call void @Whatever()
224 
225   Aggr Val = co_await AggrAwaiter{};
226   Whatever();
227   // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(ptr dead_on_unwind writable sret(%struct.Aggr) align 4 %[[AwaitResume3:.+]],
228   // CHECK: call void @Whatever()
229   // CHECK: call void @_ZN4AggrD1Ev(ptr {{[^,]*}} %[[AwaitResume3]])
230 }
231 
232 struct ScalarAwaiter {
233   template <typename F> void await_suspend(F);
234   bool await_ready();
235   int await_resume();
236 };
237 
238 extern "C" void UseScalar(int);
239 
240 // CHECK-LABEL: @TestScalar(
241 extern "C" void TestScalar() {
242   UseScalar(co_await ScalarAwaiter{});
243   // CHECK: %[[Result:.+]] = call i32 @_ZN13ScalarAwaiter12await_resumeEv(ptr
244   // CHECK: call void @UseScalar(i32 %[[Result]])
245 
246   int Val = co_await ScalarAwaiter{};
247   // CHECK: %[[Result2:.+]] = call i32 @_ZN13ScalarAwaiter12await_resumeEv(ptr
248   // CHECK: store i32 %[[Result2]], ptr %[[TMP_EXPRCLEANUP:.+]],
249   // CHECK: %[[TMP:.+]] = load i32, ptr %[[TMP_EXPRCLEANUP]],
250   // CHECK: store i32 %[[TMP]], ptr %Val,
251 
252   co_await ScalarAwaiter{};
253   // CHECK: call i32 @_ZN13ScalarAwaiter12await_resumeEv(ptr
254 }
255 
256 // Test operator co_await codegen.
257 enum class MyInt: int {};
258 ScalarAwaiter operator co_await(MyInt);
259 
260 struct MyAgg {
261   AggrAwaiter operator co_await();
262 };
263 
264 // CHECK-LABEL: @TestOpAwait(
265 extern "C" void TestOpAwait() {
266   co_await MyInt(42);
267   // CHECK: call void @_Zaw5MyInt(i32 42)
268   // CHECK: call i32 @_ZN13ScalarAwaiter12await_resumeEv(ptr {{[^,]*}} %
269 
270   co_await MyAgg{};
271   // CHECK: call void @_ZN5MyAggawEv(ptr {{[^,]*}} %
272   // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(ptr dead_on_unwind writable sret(%struct.Aggr) align 4 %
273 }
274 
275 // CHECK-LABEL: EndlessLoop(
276 extern "C" void EndlessLoop() {
277   // CHECK: %[[FRAME:.+]] = call ptr @llvm.coro.begin(
278 
279   // See if initial_suspend was issued:
280   // ----------------------------------
281   // CHECK: call void @_ZNSt16coroutine_traitsIJvEE12promise_type15initial_suspendEv(
282   // CHECK-NEXT: call zeroext i1 @_ZN9init_susp11await_readyEv(ptr
283 
284   for (;;)
285     co_await suspend_always{};
286 
287   // Verify that final_suspend was NOT issued:
288   // ----------------------------------
289   // CHECK-NOT: call void @_ZNSt16coroutine_traitsIJvEE12promise_type13final_suspendEv(
290   // CHECK-NOT: call zeroext i1 @_ZN10final_susp11await_readyEv(ptr
291 }
292 
293 // Verifies that we don't crash when awaiting on an lvalue.
294 // CHECK-LABEL: @_Z11AwaitLValuev(
295 void AwaitLValue() {
296   suspend_always lval;
297   co_await lval;
298 }
299 
300 struct RefTag { };
301 
302 struct AwaitResumeReturnsLValue {
303   bool await_ready();
304   void await_suspend(std::coroutine_handle<>);
305   RefTag& await_resume();
306 };
307 
308 template <>
309 struct std::coroutine_traits<void, double> {
310   struct promise_type {
311     void get_return_object();
312     init_susp initial_suspend();
313     final_susp final_suspend() noexcept;
314     void return_void();
315     AwaitResumeReturnsLValue yield_value(int);
316   };
317 };
318 
319 // Verifies that we don't crash when returning an lvalue from an await_resume()
320 // expression.
321 // CHECK-LABEL:  define{{.*}} void @_Z18AwaitReturnsLValued(double %0)
322 void AwaitReturnsLValue(double) {
323   AwaitResumeReturnsLValue a;
324   // CHECK: %[[AVAR:.+]] = alloca %struct.AwaitResumeReturnsLValue,
325   // CHECK: %[[XVAR:.+]] = alloca ptr,
326 
327   // CHECK: %[[YVAR:.+]] = alloca ptr,
328   // CHECK-NEXT: %[[TMP1:.+]] = alloca %struct.AwaitResumeReturnsLValue,
329 
330   // CHECK: %[[TMP_EXPRCLEANUP1:.+]] = alloca ptr,
331   // CHECK: %[[ZVAR:.+]] = alloca ptr,
332   // CHECK-NEXT: %[[TMP2:.+]] = alloca %struct.AwaitResumeReturnsLValue,
333   // CHECK: %[[TMP_EXPRCLEANUP2:.+]] = alloca ptr,
334 
335   // CHECK: %[[RES1:.+]] = call nonnull align 1 dereferenceable({{.*}}) ptr @_ZN24AwaitResumeReturnsLValue12await_resumeEv(ptr {{[^,]*}} %[[AVAR]])
336   // CHECK-NEXT: store ptr %[[RES1]], ptr %[[XVAR]],
337   RefTag& x = co_await a;
338 
339   // CHECK: %[[RES2:.+]] = call nonnull align 1 dereferenceable({{.*}}) ptr @_ZN24AwaitResumeReturnsLValue12await_resumeEv(ptr {{[^,]*}} %[[TMP1]])
340   // CHECK-NEXT: store ptr %[[RES2]], ptr %[[TMP_EXPRCLEANUP1]],
341   // CHECK: %[[LOAD_TMP1:.+]] = load ptr, ptr %[[TMP_EXPRCLEANUP1]],
342   // CHECK: store ptr %[[LOAD_TMP1]], ptr %[[YVAR]],
343 
344   RefTag& y = co_await AwaitResumeReturnsLValue{};
345   // CHECK: %[[RES3:.+]] = call nonnull align 1 dereferenceable({{.*}}) ptr @_ZN24AwaitResumeReturnsLValue12await_resumeEv(ptr {{[^,]*}} %[[TMP2]])
346   // CHECK-NEXT: store ptr %[[RES3]], ptr %[[TMP_EXPRCLEANUP2]],
347   // CHECK: %[[LOAD_TMP2:.+]] = load ptr, ptr %[[TMP_EXPRCLEANUP2]],
348   // CHECK: store ptr %[[LOAD_TMP2]], ptr %[[ZVAR]],
349   RefTag& z = co_yield 42;
350 }
351 
352 struct TailCallAwait {
353   bool await_ready();
354   std::coroutine_handle<> await_suspend(std::coroutine_handle<>);
355   void await_resume();
356 };
357 
358 // CHECK-LABEL: @TestTailcall(
359 extern "C" void TestTailcall() {
360   // CHECK: %[[PROMISE:.+]] = alloca %"struct.std::coroutine_traits<void>::promise_type"
361   // CHECK: %[[FRAME:.+]] = call ptr @llvm.coro.begin(
362   co_await TailCallAwait{};
363   // CHECK: %[[READY:.+]] = call zeroext i1 @_ZN13TailCallAwait11await_readyEv(ptr {{[^,]*}} %[[AWAITABLE:.+]])
364   // CHECK: br i1 %[[READY]], label %[[READY_BB:.+]], label %[[SUSPEND_BB:.+]]
365 
366   // If we are suspending:
367   // ---------------------
368   // CHECK: [[SUSPEND_BB]]:
369   // CHECK: %[[SUSPEND_ID:.+]] = call token @llvm.coro.save(
370   // ---------------------------
371   // Call coro.await.suspend
372   // ---------------------------
373   // Note: The call must not be nounwind since the resumed function could throw.
374   // CHECK-NEXT: call void @llvm.coro.await.suspend.handle(ptr %[[AWAITABLE]], ptr %[[FRAME]], ptr @TestTailcall.__await_suspend_wrapper__await){{$}}
375   // CHECK-NEXT: %[[OUTCOME:.+]] = call i8 @llvm.coro.suspend(token %[[SUSPEND_ID]], i1 false)
376   // CHECK-NEXT: switch i8 %[[OUTCOME]], label %[[RET_BB:.+]] [
377   // CHECK-NEXT:   i8 0, label %[[READY_BB]]
378   // CHECK-NEXT:   i8 1, label %{{.+}}
379   // CHECK-NEXT: ]
380 
381   // Await suspend wrapper
382   // CHECK: define {{.*}} ptr @TestTailcall.__await_suspend_wrapper__await(ptr {{[^,]*}} %[[AWAITABLE_ARG:.+]], ptr {{[^,]*}} %[[FRAME_ARG:.+]])
383   // CHECK: store ptr %[[AWAITABLE_ARG]], ptr %[[AWAITABLE_TMP:.+]],
384   // CHECK: store ptr %[[FRAME_ARG]], ptr %[[FRAME_TMP:.+]],
385   // CHECK: %[[AWAITABLE:.+]] = load ptr, ptr %[[AWAITABLE_TMP]]
386   // CHECK: %[[FRAME:.+]] = load ptr, ptr %[[FRAME_TMP]]
387   // CHECK: call ptr  @_ZNSt16coroutine_handleINSt16coroutine_traitsIJvEE12promise_typeEE12from_addressEPv(ptr %[[FRAME]])
388   //   ... many lines of code to coerce coroutine_handle into an ptr scalar
389   // CHECK: %[[CH:.+]] = load ptr, ptr %{{.+}}
390   // CHECK-NEXT: %[[RESULT:.+]] = call ptr @_ZN13TailCallAwait13await_suspendESt16coroutine_handleIvE(ptr {{[^,]*}} %[[AWAITABLE]], ptr %[[CH]])
391   // CHECK-NEXT: %[[COERCE:.+]] = getelementptr inbounds nuw %"struct.std::coroutine_handle", ptr %[[TMP:.+]], i32 0, i32 0
392   // CHECK-NEXT: store ptr %[[RESULT]], ptr %[[COERCE]]
393   // CHECK-NEXT: %[[ADDR:.+]] = call ptr @_ZNSt16coroutine_handleIvE7addressEv(ptr {{[^,]*}} %[[TMP]])
394   // CHECK-NEXT: ret ptr %[[ADDR]]
395 }
396