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