llvm-project/clang/test/CodeGenCoroutines
Xun Li c7a39c833a [Coroutine][Clang] Force emit lifetime intrinsics for Coroutines
tl;dr Correct implementation of Corouintes requires having lifetime intrinsics available.

Coroutine functions are functions that can be suspended and resumed latter. To do so, data that need to stay alive after suspension must be put on the heap (i.e. the coroutine frame).
The optimizer is responsible for analyzing each AllocaInst and figure out whether it should be put on the stack or the frame.
In most cases, for data that we are unable to accurately analyze lifetime, we can just conservatively put them on the heap.
Unfortunately, there exists a few cases where certain data MUST be put on the stack, not on the heap. Without lifetime intrinsics, we are unable to correctly analyze those data's lifetime.

To dig into more details, there exists cases where at certain code points, the current coroutine frame may have already been destroyed. Hence no frame access would be allowed beyond that point.
The following is a common code pattern called "Symmetric Transfer" in coroutine:
```
auto tmp = await_suspend();
__builtin_coro_resume(tmp.address());
return;
```
In the above code example, `await_suspend()` returns a new coroutine handle, which we will obtain the address and then resume that coroutine. This essentially "transfered" from the current coroutine to a different coroutine.
During the call to `await_suspend()`, the current coroutine may be destroyed, which should be fine because we are not accessing any data afterwards.
However when LLVM is emitting IR for the above code, it needs to emit an AllocaInst for `tmp`. It will then call the `address` function on tmp. `address` function is a member function of coroutine, and there is no way for the LLVM optimizer to know that it does not capture the `tmp` pointer. So when the optimizer looks at it, it has to conservatively assume that `tmp` may escape and hence put it on the heap. Furthermore, in some cases `address` call would be inlined, which will generate a bunch of store/load instructions that move the `tmp` pointer around. Those stores will also make the compiler to think that `tmp` might escape.
To summarize, it's really difficult for the mid-end to figure out that the `tmp` data is short-lived.
I made some attempt in D98638, but it appears to be way too complex and is basically doing the same thing as inserting lifetime intrinsics in coroutines.

Also, for reference, we already force emitting lifetime intrinsics in O0 for AlwaysInliner: https://github.com/llvm/llvm-project/blob/main/llvm/lib/Passes/PassBuilder.cpp#L1893

Differential Revision: https://reviews.llvm.org/D99227
2021-03-25 13:46:20 -07:00
..
Inputs [Coroutine][Sema] Tighten the lifetime of symmetric transfer returned handle 2020-09-11 13:35:37 -07:00
coro-alloc.cpp [Coroutine][Clang] Force emit lifetime intrinsics for Coroutines 2021-03-25 13:46:20 -07:00
coro-always-inline.cpp [Coroutines] Ensure co_await promise.final_suspend() does not throw 2020-06-22 15:01:42 -07:00
coro-await-domination.cpp [Coroutines] Ensure co_await promise.final_suspend() does not throw 2020-06-22 15:01:42 -07:00
coro-await-resume-eh.cpp [Coroutine][Clang] Force emit lifetime intrinsics for Coroutines 2021-03-25 13:46:20 -07:00
coro-await.cpp [Coroutine][Clang] Force emit lifetime intrinsics for Coroutines 2021-03-25 13:46:20 -07:00
coro-builtins-err.c
coro-builtins.c
coro-cleanup.cpp [test] Add {{.*}} to make ELF tests immune to dso_local/dso_preemptable/(none) differences 2020-12-31 00:27:11 -08:00
coro-dest-slot.cpp [Coroutine][Clang] Force emit lifetime intrinsics for Coroutines 2021-03-25 13:46:20 -07:00
coro-eh-cleanup.cpp
coro-gro-nrvo.cpp [test] Add {{.*}} to make ELF tests immune to dso_local/dso_preemptable/(none) differences 2020-12-31 00:27:11 -08:00
coro-gro.cpp [test] Add {{.*}} to make ELF tests immune to dso_local/dso_preemptable/(none) differences 2020-12-31 00:27:11 -08:00
coro-lambda.cpp
coro-newpm-pipeline.cpp [Coroutines] Ensure co_await promise.final_suspend() does not throw 2020-06-22 15:01:42 -07:00
coro-params.cpp [Coroutine][Clang] Force emit lifetime intrinsics for Coroutines 2021-03-25 13:46:20 -07:00
coro-promise-dtor.cpp [Coroutines] Ensure co_await promise.final_suspend() does not throw 2020-06-22 15:01:42 -07:00
coro-ret-void.cpp [test] Add {{.*}} to make ELF tests immune to dso_local/dso_preemptable/(none) differences 2020-12-31 00:27:11 -08:00
coro-return-voidtype-initlist.cpp [CodeGen] Apply 'nonnull' and 'dereferenceable(N)' to 'this' pointer 2020-11-16 17:39:17 -08:00
coro-return.cpp [CodeGen] Apply 'nonnull' and 'dereferenceable(N)' to 'this' pointer 2020-11-16 17:39:17 -08:00
coro-symmetric-transfer-01.cpp [Coroutine][Clang] Force emit lifetime intrinsics for Coroutines 2021-03-25 13:46:20 -07:00
coro-symmetric-transfer-02.cpp [test] Add {{.*}} to make ELF tests immune to dso_local/dso_preemptable/(none) differences 2020-12-31 00:27:11 -08:00
coro-unhandled-exception.cpp [Coroutine][Clang] Force emit lifetime intrinsics for Coroutines 2021-03-25 13:46:20 -07:00
microsoft-abi-operator-coawait.cpp