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 void *address();
16 };
17
18 template <typename Promise>
19 struct coroutine_handle : coroutine_handle<> {
20 static coroutine_handle from_address(void *) noexcept;
21 };
22
23 }
24 }
25
26 struct init_susp {
27 bool await_ready();
28 void await_suspend(std::experimental::coroutine_handle<>);
29 void await_resume();
30 };
31 struct final_susp {
32 bool await_ready() noexcept;
33 void await_suspend(std::experimental::coroutine_handle<>) noexcept;
34 void await_resume() noexcept;
35 };
36
37 struct suspend_always {
38 int stuff;
39 bool await_ready();
40 void await_suspend(std::experimental::coroutine_handle<>);
41 void await_resume();
42 };
43
44 template<>
45 struct std::experimental::coroutine_traits<void> {
46 struct promise_type {
47 void get_return_object();
48 init_susp initial_suspend();
49 final_susp final_suspend() noexcept;
50 void return_void();
51 };
52 };
53
54 // CHECK-LABEL: f0(
f0()55 extern "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
108 struct 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
117 template<>
118 struct 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() noexcept;
123 void return_void();
124 suspend_maybe yield_value(int);
125 };
126 };
127
128 // CHECK-LABEL: f1(
f1(int)129 extern "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(%struct.suspend_maybe) align 4 %[[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
163 struct ComplexAwaiter {
164 template <typename F> void await_suspend(F);
165 bool await_ready();
166 _Complex float await_resume();
167 };
168 extern "C" void UseComplex(_Complex float);
169
170 // CHECK-LABEL: @TestComplex(
TestComplex()171 extern "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
183 struct Aggr { int X, Y, Z; ~Aggr(); };
184 struct AggrAwaiter {
185 template <typename F> void await_suspend(F);
186 bool await_ready();
187 Aggr await_resume();
188 };
189
190 extern "C" void Whatever();
191 extern "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(
TestAggr()197 extern "C" void TestAggr() {
198 UseAggr(co_await AggrAwaiter{});
199 Whatever();
200 // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret(%struct.Aggr) align 4 %[[AwaitResume:.+]],
201 // CHECK: call void @UseAggr(%struct.Aggr* nonnull align 4 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(%struct.Aggr) align 4 %[[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(%struct.Aggr) align 4 %[[AwaitResume3:.+]],
214 // CHECK: call void @Whatever()
215 // CHECK: call void @_ZN4AggrD1Ev(%struct.Aggr* {{[^,]*}} %[[AwaitResume3]])
216 }
217
218 struct ScalarAwaiter {
219 template <typename F> void await_suspend(F);
220 bool await_ready();
221 int await_resume();
222 };
223
224 extern "C" void UseScalar(int);
225
226 // CHECK-LABEL: @TestScalar(
TestScalar()227 extern "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.
241 enum class MyInt: int {};
242 ScalarAwaiter operator co_await(MyInt);
243
244 struct MyAgg {
245 AggrAwaiter operator co_await();
246 };
247
248 // CHECK-LABEL: @TestOpAwait(
TestOpAwait()249 extern "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(%struct.Aggr) align 4 %
257 }
258
259 // CHECK-LABEL: EndlessLoop(
EndlessLoop()260 extern "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(
AwaitLValue()279 void AwaitLValue() {
280 suspend_always lval;
281 co_await lval;
282 }
283
284 struct RefTag { };
285
286 struct AwaitResumeReturnsLValue {
287 bool await_ready();
288 void await_suspend(std::experimental::coroutine_handle<>);
289 RefTag& await_resume();
290 };
291
292
293 template<>
294 struct 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() noexcept;
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 %0)
AwaitReturnsLValue(double)307 void 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 nonnull align 1 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 nonnull align 1 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 nonnull align 1 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
331 struct 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(
TestTailcall()338 extern "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