[coroutines] Add emission of initial and final suspends

https://reviews.llvm.org/D31608

llvm-svn: 303603
This commit is contained in:
Gor Nishanov 2017-05-23 05:04:01 +00:00
parent c46203eaf5
commit 5efc61866d
3 changed files with 58 additions and 11 deletions

View File

@ -388,7 +388,10 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
CurCoro.Data->FinalJD = getJumpDestInCurrentScope(FinalBB); CurCoro.Data->FinalJD = getJumpDestInCurrentScope(FinalBB);
// FIXME: Emit initial suspend and more before the body. // FIXME: Emit param moves.
CurCoro.Data->CurrentAwaitKind = AwaitKind::Init;
EmitStmt(S.getInitSuspendStmt());
CurCoro.Data->CurrentAwaitKind = AwaitKind::Normal; CurCoro.Data->CurrentAwaitKind = AwaitKind::Normal;
@ -410,7 +413,8 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
const bool HasCoreturns = CurCoro.Data->CoreturnCount > 0; const bool HasCoreturns = CurCoro.Data->CoreturnCount > 0;
if (CanFallthrough || HasCoreturns) { if (CanFallthrough || HasCoreturns) {
EmitBlock(FinalBB); EmitBlock(FinalBB);
// FIXME: Emit final suspend. CurCoro.Data->CurrentAwaitKind = AwaitKind::Final;
EmitStmt(S.getFinalSuspendStmt());
} }
} }

View File

@ -21,6 +21,17 @@ struct coroutine_handle : coroutine_handle<> {
} }
} }
struct init_susp {
bool await_ready();
void await_suspend(std::experimental::coroutine_handle<>);
void await_resume();
};
struct final_susp {
bool await_ready();
void await_suspend(std::experimental::coroutine_handle<>);
void await_resume();
};
struct suspend_always { struct suspend_always {
int stuff; int stuff;
bool await_ready(); bool await_ready();
@ -32,8 +43,8 @@ template<>
struct std::experimental::coroutine_traits<void> { struct std::experimental::coroutine_traits<void> {
struct promise_type { struct promise_type {
void get_return_object(); void get_return_object();
suspend_always initial_suspend(); init_susp initial_suspend();
suspend_always final_suspend(); final_susp final_suspend();
void return_void(); void return_void();
}; };
}; };
@ -42,6 +53,13 @@ struct std::experimental::coroutine_traits<void> {
extern "C" void f0() { extern "C" void f0() {
// CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin( // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin(
// See if initial_suspend was issued:
// ----------------------------------
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type15initial_suspendEv(
// CHECK-NEXT: call zeroext i1 @_ZN9init_susp11await_readyEv(%struct.init_susp*
// CHECK: %[[INITSP_ID:.+]] = call token @llvm.coro.save(
// CHECK: call i8 @llvm.coro.suspend(token %[[INITSP_ID]], i1 false)
co_await suspend_always{}; co_await suspend_always{};
// See if we need to suspend: // See if we need to suspend:
// -------------------------- // --------------------------
@ -76,6 +94,13 @@ extern "C" void f0() {
// -------------------------- // --------------------------
// CHECK: [[READY_BB]]: // CHECK: [[READY_BB]]:
// CHECK: call void @_ZN14suspend_always12await_resumeEv(%struct.suspend_always* %[[AWAITABLE]]) // CHECK: call void @_ZN14suspend_always12await_resumeEv(%struct.suspend_always* %[[AWAITABLE]])
// See if final_suspend was issued:
// ----------------------------------
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type13final_suspendEv(
// CHECK-NEXT: call zeroext i1 @_ZN10final_susp11await_readyEv(%struct.final_susp*
// CHECK: %[[FINALSP_ID:.+]] = call token @llvm.coro.save(
// CHECK: call i8 @llvm.coro.suspend(token %[[FINALSP_ID]], i1 true)
} }
struct suspend_maybe { struct suspend_maybe {
@ -91,8 +116,8 @@ template<>
struct std::experimental::coroutine_traits<void,int> { struct std::experimental::coroutine_traits<void,int> {
struct promise_type { struct promise_type {
void get_return_object(); void get_return_object();
suspend_always initial_suspend(); init_susp initial_suspend();
suspend_always final_suspend(); final_susp final_suspend();
void return_void(); void return_void();
suspend_maybe yield_value(int); suspend_maybe yield_value(int);
}; };
@ -228,3 +253,21 @@ extern "C" void TestOpAwait() {
// CHECK: call void @_ZN5MyAggawEv(%struct.MyAgg* % // CHECK: call void @_ZN5MyAggawEv(%struct.MyAgg* %
// CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret % // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret %
} }
// CHECK-LABEL: EndlessLoop(
extern "C" void EndlessLoop() {
// CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin(
// See if initial_suspend was issued:
// ----------------------------------
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type15initial_suspendEv(
// CHECK-NEXT: call zeroext i1 @_ZN9init_susp11await_readyEv(%struct.init_susp*
for (;;)
co_await suspend_always{};
// Verify that final_suspend was NOT issued:
// ----------------------------------
// CHECK-NOT: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type13final_suspendEv(
// CHECK-NOT: call zeroext i1 @_ZN10final_susp11await_readyEv(%struct.final_susp*
}

View File

@ -46,6 +46,11 @@ void f() {
// CHECK: invoke void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_typeC1Ev( // CHECK: invoke void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_typeC1Ev(
// CHECK-NEXT: to label %{{.+}} unwind label %[[DeallocPad:.+]] // CHECK-NEXT: to label %{{.+}} unwind label %[[DeallocPad:.+]]
// CHECK: [[DeallocPad]]:
// CHECK-NEXT: landingpad
// CHECK-NEXT: cleanup
// CHECK: br label %[[Dealloc:.+]]
Cleanup cleanup; Cleanup cleanup;
may_throw(); may_throw();
@ -54,11 +59,6 @@ void f() {
// CHECK: invoke void @_Z9may_throwv( // CHECK: invoke void @_Z9may_throwv(
// CHECK-NEXT: to label %{{.+}} unwind label %[[CatchPad:.+]] // CHECK-NEXT: to label %{{.+}} unwind label %[[CatchPad:.+]]
// CHECK: [[DeallocPad]]:
// CHECK-NEXT: landingpad
// CHECK-NEXT: cleanup
// CHECK: br label %[[Dealloc:.+]]
// CHECK: [[CatchPad]]: // CHECK: [[CatchPad]]:
// CHECK-NEXT: landingpad // CHECK-NEXT: landingpad
// CHECK-NEXT: catch i8* null // CHECK-NEXT: catch i8* null