Clang Project

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