[clang] bf5f235 - [NFC] [Coroutines] Add regression tests for symmetric transfer and coroutine elision
Chuanqi Xu via cfe-commits
cfe-commits at lists.llvm.org
Wed Jan 12 03:40:20 PST 2022
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
More information about the cfe-commits
mailing list