[llvm-dev] sret read after unwind

Nikita Popov via llvm-dev llvm-dev at lists.llvm.org
Thu Jan 6 06:42:00 PST 2022


On Tue, Jan 4, 2022 at 5:57 PM Nikita Popov <nikita.ppv at gmail.com> wrote:

> On Tue, Jan 4, 2022 at 5:27 PM Johannes Doerfert <
> johannesdoerfert at gmail.com> wrote:
>
>>
>> On 1/4/22 03:39, Nikita Popov wrote:
>> > On Mon, Jan 3, 2022 at 6:33 PM Johannes Doerfert <
>> johannesdoerfert at gmail.com>
>> > wrote:
>> >
>> >> I somewhat missed this thread and while I should maybe respond
>> >> to a few of the other mails too I figured I start with a conceptual
>> >> question I have reading this:
>> >>
>> >> Who and when is the attribute added? If it is implied by sret that's
>> >> a good start. For the non-sret deduction it seems very specialized.
>> >> I mean, now we have something for the unwind case but not a different
>> >> "early exit" or if it is read/writeonly rather than readnone.
>> >>
>> > I'm mainly interested in frontend-annotated cases here, rather than
>> deduced
>> > ones. The primary use case there is adding it to sret arguments (and
>> only
>> > changing sret semantics would be "good enough" for me, I guess).
>> However,
>> > there is another frontend-annotated case I have my eyes on, which is
>> move
>> > arguments in rust. These could be modeled by a combination of
>> > noreadonunwind and noreadonreturn to indicate that the value will not be
>> > used after the call at all, regardless of how it exits. (This would be
>> kind
>> > of similar to a byval argument, just without the ABI implication that an
>> > actual copy gets inserted.)
>>
>> OK. That's interesting. I'm not fluent enough in rust, can you
>> elaborate what the semantics there would be, maybe an IR example?
>>
>
> To give a silly example, take these two functions in rust (
> https://rust.godbolt.org/z/9cvefedsP):
>
> pub fn test1(mut s: String) {
>     s = "foobar".to_string();
> }
> pub fn test2(s: &mut String) {
>     *s = "foobar".to_string();
> }
>
> From an ABI perspective, these are basically the same. In both cases rust
> will lower this to passing in a String*. However, because String is a
> non-Copy type, any call "test(s)" will move the "s" variable, which means
> that "s" cannot be used after the call anymore. For that reason, the store
> "s =" would be definitely dead in the first example, and usually not dead
> in the second example.
>

Something I realized while looking through existing code is that there are
two different cases of "not visible after unwind/return" that usually get
handled: For allocas, this statement is absolute, and independent of
whether the alloca is captured. For returns from allocation functions, this
only holds if the pointer does not escape. If it does escape, then a write
before unwind/return might be visible to the caller.

For the sret unwind case, we can also make an absolute statement. But for
the Rust move argument case above, we can't. The pointer can be captured
(by moving it further) and accessed by the caller. One case we can treat
like an alloca, the other like a malloc().

Not really sure what to make of this yet.

Regards,
Nikita
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20220106/b9508244/attachment.html>


More information about the llvm-dev mailing list