<div dir="ltr"><div dir="ltr"></div><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Jan 4, 2022 at 5:57 PM Nikita Popov <<a href="mailto:nikita.ppv@gmail.com">nikita.ppv@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Jan 4, 2022 at 5:27 PM Johannes Doerfert <<a href="mailto:johannesdoerfert@gmail.com" target="_blank">johannesdoerfert@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br>
On 1/4/22 03:39, Nikita Popov wrote:<br>
> On Mon, Jan 3, 2022 at 6:33 PM Johannes Doerfert <<a href="mailto:johannesdoerfert@gmail.com" target="_blank">johannesdoerfert@gmail.com</a>><br>
> wrote:<br>
><br>
>> I somewhat missed this thread and while I should maybe respond<br>
>> to a few of the other mails too I figured I start with a conceptual<br>
>> question I have reading this:<br>
>><br>
>> Who and when is the attribute added? If it is implied by sret that's<br>
>> a good start. For the non-sret deduction it seems very specialized.<br>
>> I mean, now we have something for the unwind case but not a different<br>
>> "early exit" or if it is read/writeonly rather than readnone.<br>
>><br>
> I'm mainly interested in frontend-annotated cases here, rather than deduced<br>
> ones. The primary use case there is adding it to sret arguments (and only<br>
> changing sret semantics would be "good enough" for me, I guess). However,<br>
> there is another frontend-annotated case I have my eyes on, which is move<br>
> arguments in rust. These could be modeled by a combination of<br>
> noreadonunwind and noreadonreturn to indicate that the value will not be<br>
> used after the call at all, regardless of how it exits. (This would be kind<br>
> of similar to a byval argument, just without the ABI implication that an<br>
> actual copy gets inserted.)<br>
<br>
OK. That's interesting. I'm not fluent enough in rust, can you<br>
elaborate what the semantics there would be, maybe an IR example?<br></blockquote><div class="gmail_quote"><br>To give a silly example, take these two functions in rust (<a href="https://rust.godbolt.org/z/9cvefedsP" target="_blank">https://rust.godbolt.org/z/9cvefedsP</a>):<br></div><div><div class="gmail_quote"><br></div><div class="gmail_quote">pub fn test1(mut s: String) {<br>    s = "foobar".to_string();<br>}<br>pub fn test2(s: &mut String) {<br>    *s = "foobar".to_string();<br>}</div><div class="gmail_quote"><br></div><div class="gmail_quote">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.</div></div></div></div></blockquote><div><br></div><div>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.</div><div><br></div><div>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().</div><div><br></div><div>Not really sure what to make of this yet.<br></div><div><br></div><div>Regards,</div><div>Nikita<br></div></div></div>