[clang] bc11c85 - [clang][CodeGen] Emit coro.dead intrinsic to improve coroutine allocation elision (#190295)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 2 19:06:16 PDT 2026
Author: Weibo He
Date: 2026-04-03T02:06:10Z
New Revision: bc11c85b6b16f1daabfc9e8b326c9568c3318cb9
URL: https://github.com/llvm/llvm-project/commit/bc11c85b6b16f1daabfc9e8b326c9568c3318cb9
DIFF: https://github.com/llvm/llvm-project/commit/bc11c85b6b16f1daabfc9e8b326c9568c3318cb9.diff
LOG: [clang][CodeGen] Emit coro.dead intrinsic to improve coroutine allocation elision (#190295)
Part 4/4: Implement HALO for coroutines that flow off final suspend.
Parent PR: #185336
Added:
Modified:
clang/lib/CodeGen/CGCoroutine.cpp
clang/test/CodeGenCoroutines/coro-elide.cpp
Removed:
################################################################################
diff --git a/clang/lib/CodeGen/CGCoroutine.cpp b/clang/lib/CodeGen/CGCoroutine.cpp
index 7282c42420657..9d9d2450c3d68 100644
--- a/clang/lib/CodeGen/CGCoroutine.cpp
+++ b/clang/lib/CodeGen/CGCoroutine.cpp
@@ -643,6 +643,9 @@ struct CallCoroDelete final : public EHScopeStack::Cleanup {
// No longer need old terminator.
InsertPt->eraseFromParent();
CGF.Builder.SetInsertPoint(AfterFreeBB);
+
+ auto *CoroDeadFn = CGF.CGM.getIntrinsic(llvm::Intrinsic::coro_dead);
+ CGF.Builder.CreateCall(CoroDeadFn, {CGF.CurCoro.Data->CoroBegin});
}
explicit CallCoroDelete(Stmt *DeallocStmt) : Deallocate(DeallocStmt) {}
};
diff --git a/clang/test/CodeGenCoroutines/coro-elide.cpp b/clang/test/CodeGenCoroutines/coro-elide.cpp
index d7569c3b4d087..1902dd64b5e5a 100644
--- a/clang/test/CodeGenCoroutines/coro-elide.cpp
+++ b/clang/test/CodeGenCoroutines/coro-elide.cpp
@@ -1,8 +1,32 @@
-// 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"
+namespace {
+struct coro {
+ using promise_type = coro;
+
+ auto get_return_object() noexcept { return coro{std::coroutine_handle<coro>::from_promise(*this)}; }
+ std::suspend_never initial_suspend() noexcept { return {}; }
+ std::suspend_never final_suspend() noexcept { return {}; }
+ void return_void() noexcept {}
+ void unhandled_exception() {}
+
+ std::coroutine_handle<> handle;
+};
+}
+
+void flowoff() {
+ []() -> coro {
+ co_await std::suspend_always{};
+ }().handle.resume();
+}
+
+// Tests that the coroutine elide optimization could happen if control flows off the end of the coroutine
+// CHECK-LABEL: define{{.*}} void @_Z7flowoffv
+// CHECK-NEXT: entry:
+// CHECK-NEXT: ret void
+
struct Task {
struct promise_type {
struct FinalAwaiter {
@@ -58,5 +82,6 @@ Task task1() {
co_return co_await task0();
}
+// Tests that the coroutine elide optimization could happen if handle.destroy() is invoked
// CHECK-LABEL: define{{.*}} void @_Z5task1v.resume
// CHECK-NOT: call{{.*}}_Znwm
More information about the cfe-commits
mailing list