[PATCH] D104007: [BasicAA] Properly mark that coroutine suspension may modify parameters

Xun Li via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 14 09:00:50 PDT 2021


lxfind added a comment.

In D104007#2815847 <https://reviews.llvm.org/D104007#2815847>, @efriedma wrote:

> In D104007#2815732 <https://reviews.llvm.org/D104007#2815732>, @lxfind wrote:
>
>> It seems that there is no stable contract to tell whether an argument is byval, and it depends on the target. 
>> For example: https://godbolt.org/z/YcrYPbMdc
>> So we won't be able to fix this just in CoroSplit pass. Either we change the front-end to force all byval arguments to have byval attribute (not sure if that's possible), or we may have to conservatively go with this patch.
>
> I'm not sure what you mean. An LLVM IR argument either has the byval attribute, or it doesn't.  If it does, the allocation belongs to the callee.  If it doesn't, the pointer refers to an allocation constructed in the caller.  There isn't any other sense in which an argument can be "byval".
>
> A given C++ function can have a bunch of variations in the LLVM IR signature, depending on the target, but that's not relevant here.  Once clang is finished emitting IR, the C++ type signature becomes irrelevant.

Unfortunately what we really care about here is whether an argument is by-value from C++ perspective, not just whether it has a byval attribute. Let me try to explain the problem top-down and see if I got it wrong somewhere:

1. In C++, when we call a function with a parameter passed by value, such as `foo(std::move(a))`, the passed value is typically a temporary value allocated at caller, and only the pointer is passed to the callee. When callee returns, the caller will be able to deallocate that temporary value's memory (in LLVM IR terms, there will be a lifetime.end marking the temporary value after the callee returns).
2. If the callee is a normal routine (non-coroutine), the callee don't need to worry about the lifetime of the parameter because it will stay alive through the entire life cycle of the callee.
3. However if the callee is a coroutine, the situation is different because the coroutine can return in the middle of the function and latter resume. As soon as the coroutine returns for the first time (i.e. suspended the first time), the temporary value (the pass-by-value parameter) would die in the caller. But if the callee needs to use that argument after coroutine resumption, we need to make sure that the argument value will be put on the coroutine frame (similar to allocas), so that latter access won't be accessing invalid memory.
4. However there is one major difference between a parameter and an alloca: for a parameter that is a pointer type, we need to know whether we need to copy the value that the pointer points to to the coroutine frame, or just the pointer it self. For instance, you could call a coroutine by passing a direct pointer, and in that case we should only need to copy the pointer to the frame. But for the C++ pass-by-value arguments, we need to copy the value that the pointer points to to the frame. The question is then, during CoroSplit (the pass where we put things to the frame), are we able to tell, given an argument pointer, whether we need to copy the value or just the pointer to the frame? Knowing that a C++ pass-by-value argument doesn't necessarily end up with an argument with a byval attribute, we know that it is not possible to tell, hence we cannot deal with this properly only in CoroSplit pass.

That this sound right?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D104007/new/

https://reviews.llvm.org/D104007



More information about the llvm-commits mailing list