Skip to content

Commit 9d9c25f

Browse files
committed
[C++20] [Coroutines] Don't mark await_suspend as noinline if it is specified as always_inline already
Address #64933 and partially #64945. After c467245, we will add a noinline attribute to the await_suspend member function of an awaiter if the awaiter has any non static member functions. Obviously, this decision will bring some performance regressions. And people may complain about this while the long term solution may not be available soon. In such cases, it is better to provide a solution for the users who met the regression surprisingly. Also it is natural to not prevent the inlining if the function is marked as always_inline by the users already.
1 parent 57aee4e commit 9d9c25f

File tree

2 files changed

+22
-1
lines changed

2 files changed

+22
-1
lines changed

clang/lib/CodeGen/CGCall.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5548,7 +5548,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
55485548
// Then it is much easier to perform the safety analysis in the middle end.
55495549
// If it is safe to inline the call to awaitSuspend, we can replace it in the
55505550
// CoroEarly pass. Otherwise we could replace it in the CoroSplit pass.
5551-
if (inSuspendBlock() && mayCoroHandleEscape())
5551+
//
5552+
// If the `await_suspend()` function is marked as `always_inline` explicitly,
5553+
// we should give the user the right to control the codegen.
5554+
if (inSuspendBlock() && mayCoroHandleEscape() &&
5555+
!TargetDecl->hasAttr<AlwaysInlineAttr>())
55525556
Attrs = Attrs.addFnAttribute(getLLVMContext(), llvm::Attribute::NoInline);
55535557

55545558
// Disable inlining inside SEH __try blocks.

clang/test/CodeGenCoroutines/coro-awaiter-noinline-suspend.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,17 @@ StatefulAwaiter& operator co_await(Awaitable2) {
6767
return GlobalAwaiter;
6868
}
6969

70+
struct AlwaysInlineStatefulAwaiter {
71+
void* value;
72+
bool await_ready() const noexcept { return false; }
73+
74+
template <typename PromiseType>
75+
__attribute__((always_inline))
76+
void await_suspend(std::coroutine_handle<PromiseType> h) noexcept {}
77+
78+
void await_resume() noexcept {}
79+
};
80+
7081
Task testing() {
7182
co_await std::suspend_always{};
7283
co_await StatefulAwaiter{};
@@ -85,6 +96,8 @@ Task testing() {
8596

8697
co_await Awaitable{};
8798
co_await Awaitable2{};
99+
100+
co_await AlwaysInlineStatefulAwaiter{};
88101
}
89102

90103
// CHECK-LABEL: @_Z7testingv
@@ -135,6 +148,10 @@ Task testing() {
135148
// CHECK: call token @llvm.coro.save
136149
// CHECK: call void @_ZN15StatefulAwaiter13await_suspendIN4Task12promise_typeEEEvSt16coroutine_handleIT_E{{.*}}#[[NOINLINE_ATTR]]
137150

151+
// Check `co_await AlwaysInlineStatefulAwaiter{};` to make sure user can force the await_suspend function to get inlined.
152+
// CHECK: call token @llvm.coro.save
153+
// CHECK: call void @_ZN27AlwaysInlineStatefulAwaiter13await_suspendIN4Task12promise_typeEEEvSt16coroutine_handleIT_E{{.*}}#[[NORMAL_ATTR]]
154+
138155
// Check `co_await __promise__.final_suspend();`. We don't emit an blocker here since it is
139156
// empty.
140157
// CHECK: call token @llvm.coro.save

0 commit comments

Comments
 (0)