<div dir="ltr"><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Jan 4, 2022 at 6:15 PM Johannes Doerfert <<a href="mailto:johannesdoerfert@gmail.com">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 10:57, Nikita Popov wrote:<br>
> On Tue, Jan 4, 2022 at 5:27 PM Johannes Doerfert <<a href="mailto:johannesdoerfert@gmail.com" target="_blank">johannesdoerfert@gmail.com</a>><br>
> wrote:<br>
><br>
>> On 1/4/22 03:39, Nikita Popov wrote:<br>
>>> On Mon, Jan 3, 2022 at 6:33 PM Johannes Doerfert <<br>
>> <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<br>
>> 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<br>
>> kind<br>
>>> of similar to a byval argument, just without the ABI implication that an<br>
>>> actual copy gets inserted.)<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>
>><br>
> To give a silly example, take these two functions in rust (<br>
> <a href="https://rust.godbolt.org/z/9cvefedsP" rel="noreferrer" target="_blank">https://rust.godbolt.org/z/9cvefedsP</a>):<br>
><br>
> 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>
> }<br>
><br>
>  From an ABI perspective, these are basically the same. In both cases rust<br>
> will lower this to passing in a String*. However, because String is a<br>
> non-Copy type, any call "test(s)" will move the "s" variable, which means<br>
> that "s" cannot be used after the call anymore. For that reason, the store<br>
> "s =" would be definitely dead in the first example, and usually not dead<br>
> in the second example.<br>
><br>
I see. Again just as an idea, what if we make the "overwriting stores"<br>
explicit instead of using attributes.<br>
<br>
```<br>
s = "foobar".to_string();<br>
// other code<br>
virtual_memset(s, sizeof(s), 0);<br>
ret void<br>
```<br>
<br>
Now DSE will do the work for us.<br>
It is not clear if we could do something similar for the other cases<br>
though.<br>
<br>
Whatever we do, I can see how this is information that is worth encoding.<br></blockquote><div><br></div><div>Yeah, doing this kind of memset would encode the necessary information for the return case -- I don't think it would be a good fit for the unwind case, because it would require you to make all the unwind paths in the function explicit. I think we already have this "virtual_memset" and it's called llvm.lifetime.end -- just that nobody really understands its semantics when it comes to non-alloca objects. In this case we'd have to have the lifetime.start and lifetime.end in separate functions, which would probably be all kinds of trouble :)<br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

>> Spitballing: `byval(nocopy, %a)` might be worth thinking about<br>
>> given the short description.<br>
>><br>
> Yeah, I guess that would work -- though I'd rather not mix ABI and<br>
> optimization attributes in that way...<br>
><br>
>>> Note that as proposed, the noreadonunwind attribute would be the<br>
>> "writeonly<br>
>>> on unwind" combination (and noreadonreturn the "writeonly on return"<br>
>>> combination). I can see that there are conjugated "readonly on unwind"<br>
>> and<br>
>>> "readonly on return" attributes that could be defined here, but I can't<br>
>>> think of any circumstances under which these would actually be useful for<br>
>>> optimization purposes. How would the presence or absence of later writes<br>
>>> impact optimization in the current function?<br>
>> Just as an example, `readonly on unwind` allows you to do GVN/CSE<br>
>> from prior to the call to the "unwind path". Return then on the<br>
>> "return path". That is not inside the call but in the caller.<br>
>> Does that make sense?<br>
><br>
> Let me check if I understood the idea right: We have a invoke with a<br>
> hypothetical "readonly on unwind" / "no write on unwind" attribute. In the<br>
> landing pad, there is a non-analyzable write and the pointer has previously<br>
> escaped, and then later there is a read from the argument. The<br>
> non-analyzable write blocks AA, while the "readonly on unwind" guarantee<br>
> could make a sufficiently smart AA see that this write cannot write into<br>
> the argument memory. Is that the idea? I feel like "readonly on unwind"<br>
> isn't the right way to model that situation, rather the argument could be<br>
> marked as invariant in the unwind path using one of our existing ways to<br>
> denote invariance.<br>
><br>
> But I suspect I still didn't quite get what you have in mind here. An<br>
> example would help.<br>
<br>
Maybe I am confused but I thought something like this pseudo-code<br>
could be optimized, readonly_on_return is similar.<br>
<br>
```<br>
int a = 42;<br>
invoke foo(/* readonly_on_unwind */ &a);<br>
lp:<br>
   return a; // a == 42<br>
cont:<br>
   return a; // a unknown<br>
```<br></blockquote><div><br></div><div>Okay, I guess there's a possible point of confusion here: The intention here is that the attribute encodes a requirement on accesses *after* the call. readonly_on_unwind would allow only reading "a" in "lp", but does not prevent foo() from modifying "a" even if it ultimately unwinds. With that in mind, I don't think the attribute would enable any additional optimization here.<br></div><div><br></div><div>So maybe the proposed attribute is better named as "noreadafterunwind" rather than "noreadonunwind".<br></div></div><div class="gmail_quote"><br></div><div class="gmail_quote">Regards,</div><div class="gmail_quote">Nikita<br></div></div>