[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