Author: Chuanqi Xu Date: 2022-01-12T19:39:56+08:00 New Revision: bf5f2354fa6e3f31a1acea75a229fee54359e279
URL: https://github.com/llvm/llvm-project/commit/bf5f2354fa6e3f31a1acea75a229fee54359e279 DIFF: https://github.com/llvm/llvm-project/commit/bf5f2354fa6e3f31a1acea75a229fee54359e279.diff LOG: [NFC] [Coroutines] Add regression tests for symmetric transfer and coroutine elision Added: clang/test/CodeGenCoroutines/coro-elide.cpp clang/test/CodeGenCoroutines/coro-symmetric-transfer-03.cpp Modified: clang/test/CodeGenCoroutines/Inputs/coroutine.h Removed: ################################################################################ diff --git a/clang/test/CodeGenCoroutines/Inputs/coroutine.h b/clang/test/CodeGenCoroutines/Inputs/coroutine.h index 7c2d363f8890..4473bcc95c09 100644 --- a/clang/test/CodeGenCoroutines/Inputs/coroutine.h +++ b/clang/test/CodeGenCoroutines/Inputs/coroutine.h @@ -1,3 +1,4 @@ +// This is a mock file for <coroutine>. #pragma once namespace std { @@ -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 {} diff --git a/clang/test/CodeGenCoroutines/coro-elide.cpp b/clang/test/CodeGenCoroutines/coro-elide.cpp new file mode 100644 index 000000000000..6fccff424d93 --- /dev/null +++ b/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 diff --git a/clang/test/CodeGenCoroutines/coro-symmetric-transfer-03.cpp b/clang/test/CodeGenCoroutines/coro-symmetric-transfer-03.cpp new file mode 100644 index 000000000000..33384b2f4839 --- /dev/null +++ b/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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits