[all-commits] [llvm/llvm-project] b32aa7: Recommit [C++20] [Coroutines] Mark await_suspend a...

Chuanqi Xu via All-commits all-commits at lists.llvm.org
Mon Aug 28 02:14:09 PDT 2023

  Branch: refs/heads/main
  Home:   https://github.com/llvm/llvm-project
  Commit: b32aa72afc1d6a094fde6ca04d8a1124af34a2ad
  Author: Chuanqi Xu <yedeng.yd at linux.alibaba.com>
  Date:   2023-08-28 (Mon, 28 Aug 2023)

  Changed paths:
    M clang/docs/ReleaseNotes.rst
    M clang/lib/CodeGen/CGCoroutine.cpp
    M clang/lib/Sema/SemaCoroutine.cpp
    A clang/test/CodeGenCoroutines/coro-awaiter-noinline-suspend.cpp
    A clang/test/CodeGenCoroutines/pr56301.cpp
    A clang/test/CodeGenCoroutines/pr65018.cpp

  Log Message:
  Recommit [C++20] [Coroutines] Mark await_suspend as noinline if the awaiter is not empty

The original patch is incorrect since it marks too many calls to be
noinline. It shows that it is bad to do analysis in the frontend again.
This patch tries to mark the await_suspend function as noinlne only.


Close https://github.com/llvm/llvm-project/issues/56301
Close https://github.com/llvm/llvm-project/issues/64151
Close https://github.com/llvm/llvm-project/issues/65018

See the summary and the discussion of
to get the full context.

As @rjmccall pointed out, the key point of the root cause is that
currently we didn't implement the semantics for '@llvm.coro.save'
well ("after the await-ready returns false, the coroutine is considered
to be suspended ") well.
Since the semantics implies that we (the compiler) shouldn't write
the spills into the coroutine frame in the await_suspend. But now it is
possible due to some combinations of the optimizations so the semantics are
broken. And the inlining is the root optimization of such optimizations.
So in this patch, we tried to add the `noinline` attribute to the
await_suspend function.

This looks slightly problematic since the users are able to call the
await_suspend function standalone. This is limited by the
implementation. On the one hand, we don't want the workaround solution
(See the proposed solution later) to be too complex. On the other hand,
it is rare to call await_suspend standalone. Also it is not semantically
incorrect to do so since the inlining is not part of the C++ standard.

Also as an optimization, we don't add the `noinline` attribute to
the await_suspend function if the awaiter is an empty class. This should be
correct since the programmers can't access the local variables in
await_suspend if the awaiter is empty. I think this is necessary for
the performance since it is pretty common.

The long term solution is:

    call @llvm.coro.await_suspend(ptr %awaiter, ptr %handle,
                                  ptr @awaitSuspendFn)

Then it is much easier to perform the safety analysis in the middle
end. If it is safe to inline the call to awaitSuspend, we can replace it
in the CoroEarly pass. Otherwise we could replace it in the CoroSplit

Reviewed By: rjmccall

Differential Revision: https://reviews.llvm.org/D157833

More information about the All-commits mailing list