Skip to content

Commit

Permalink
[NFC] [Coroutines] Add regression tests for symmetric transfer and co…
Browse files Browse the repository at this point in the history
…routine elision
  • Loading branch information
ChuanqiXu9 committed Jan 12, 2022
1 parent de05128 commit bf5f235
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 10 deletions.
55 changes: 45 additions & 10 deletions clang/test/CodeGenCoroutines/Inputs/coroutine.h
@@ -1,3 +1,4 @@
// This is a mock file for <coroutine>.
#pragma once

namespace std {
Expand Down Expand Up @@ -52,20 +53,54 @@ template <typename Promise> struct coroutine_handle : coroutine_handle<> {
}
};

template <typename _PromiseT>
bool operator==(coroutine_handle<_PromiseT> const& _Left,
coroutine_handle<_PromiseT> const& _Right) noexcept
{
return _Left.address() == _Right.address();
template <typename _PromiseT>
bool operator==(coroutine_handle<_PromiseT> const &_Left,
coroutine_handle<_PromiseT> const &_Right) noexcept {
return _Left.address() == _Right.address();
}

template <typename _PromiseT>
bool operator!=(coroutine_handle<_PromiseT> const &_Left,
coroutine_handle<_PromiseT> const &_Right) noexcept {
return !(_Left == _Right);
}

struct noop_coroutine_promise {};

template <>
struct coroutine_handle<noop_coroutine_promise> {
operator coroutine_handle<>() const noexcept {
return coroutine_handle<>::from_address(address());
}

template <typename _PromiseT>
bool operator!=(coroutine_handle<_PromiseT> const& _Left,
coroutine_handle<_PromiseT> const& _Right) noexcept
{
return !(_Left == _Right);
constexpr explicit operator bool() const noexcept { return true; }
constexpr bool done() const noexcept { return false; }

constexpr void operator()() const noexcept {}
constexpr void resume() const noexcept {}
constexpr void destroy() const noexcept {}

noop_coroutine_promise &promise() const noexcept {
return *static_cast<noop_coroutine_promise *>(
__builtin_coro_promise(this->__handle_, alignof(noop_coroutine_promise), false));
}

constexpr void *address() const noexcept { return __handle_; }

private:
friend coroutine_handle<noop_coroutine_promise> noop_coroutine() noexcept;

coroutine_handle() noexcept {
this->__handle_ = __builtin_coro_noop();
}

void *__handle_ = nullptr;
};

using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;

inline noop_coroutine_handle noop_coroutine() noexcept { return noop_coroutine_handle(); }

struct suspend_always {
bool await_ready() noexcept { return false; }
void await_suspend(coroutine_handle<>) noexcept {}
Expand Down
63 changes: 63 additions & 0 deletions clang/test/CodeGenCoroutines/coro-elide.cpp
@@ -0,0 +1,63 @@
// This tests that the coroutine elide optimization could happen succesfully.
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -O2 -emit-llvm %s -o - | FileCheck %s

#include "Inputs/coroutine.h"

struct Task {
struct promise_type {
struct FinalAwaiter {
bool await_ready() const noexcept { return false; }
template <typename PromiseType>
std::coroutine_handle<> await_suspend(std::coroutine_handle<PromiseType> h) noexcept {
if (!h)
return std::noop_coroutine();
return h.promise().continuation;
}
void await_resume() noexcept {}
};
Task get_return_object() noexcept {
return std::coroutine_handle<promise_type>::from_promise(*this);
}
std::suspend_always initial_suspend() noexcept { return {}; }
FinalAwaiter final_suspend() noexcept { return {}; }
void unhandled_exception() noexcept {}
void return_value(int x) noexcept {
_value = x;
}
std::coroutine_handle<> continuation;
int _value;
};

Task(std::coroutine_handle<promise_type> handle) : handle(handle) {}
~Task() {
if (handle)
handle.destroy();
}

struct Awaiter {
bool await_ready() const noexcept { return false; }
void await_suspend(std::coroutine_handle<void> continuation) noexcept {}
int await_resume() noexcept {
return 43;
}
};

auto operator co_await() {
return Awaiter{};
}

private:
std::coroutine_handle<promise_type> handle;
};

Task task0() {
co_return 43;
}

Task task1() {
co_return co_await task0();
}

// CHECK: %_Z5task1v.Frame = type {{.*}}%_Z5task0v.Frame
// CHECK-LABEL: define{{.*}} void @_Z5task1v.resume
// CHECK-NOT: call{{.*}}_Znwm
68 changes: 68 additions & 0 deletions clang/test/CodeGenCoroutines/coro-symmetric-transfer-03.cpp
@@ -0,0 +1,68 @@
// This tests that the symmetric transfer at the final suspend point could happen successfully.
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -O2 -emit-llvm %s -o - | FileCheck %s

#include "Inputs/coroutine.h"

struct Task {
struct promise_type {
struct FinalAwaiter {
bool await_ready() const noexcept { return false; }
template <typename PromiseType>
std::coroutine_handle<> await_suspend(std::coroutine_handle<PromiseType> h) noexcept {
return h.promise().continuation;
}
void await_resume() noexcept {}
};
Task get_return_object() noexcept {
return std::coroutine_handle<promise_type>::from_promise(*this);
}
std::suspend_always initial_suspend() noexcept { return {}; }
FinalAwaiter final_suspend() noexcept { return {}; }
void unhandled_exception() noexcept {}
void return_value(int x) noexcept {
_value = x;
}
std::coroutine_handle<> continuation;
int _value;
};

Task(std::coroutine_handle<promise_type> handle) : handle(handle) {}
~Task() {
if (handle)
handle.destroy();
}

struct Awaiter {
std::coroutine_handle<promise_type> handle;
Awaiter(std::coroutine_handle<promise_type> handle) : handle(handle) {}
bool await_ready() const noexcept { return false; }
std::coroutine_handle<void> await_suspend(std::coroutine_handle<void> continuation) noexcept {
handle.promise().continuation = continuation;
return handle;
}
int await_resume() noexcept {
int ret = handle.promise()._value;
handle.destroy();
return ret;
}
};

auto operator co_await() {
auto handle_ = handle;
handle = nullptr;
return Awaiter(handle_);
}

private:
std::coroutine_handle<promise_type> handle;
};

Task task0() {
co_return 43;
}

// CHECK-LABEL: define{{.*}} void @_Z5task0v.resume
// This checks we are still in the scope of the current function.
// CHECK-NOT: {{^}}}
// CHECK: musttail call fastcc void
// CHECK-NEXT: ret void

0 comments on commit bf5f235

Please sign in to comment.