<div dir="ltr">Yea, I'm pretty sad about all of this. I'm also not seeing a lot of awesome paths forward.<div><br></div><div>Here is the least bad strategy I can come up with. Curious if folks think this is sufficient:</div><div><br></div><div>1) Stop deducing function attributes within comdats by examining the bodies of the functions (so that we remain free to transform the bodies of functions).</div><div>2) Teach frontends to emit (even at O0!!!) trivially deduced function attributes for comdats so that we continue to catch easy cases.</div><div>3) Ensure and specify that we never hoist code *into* a comdat group in which it would not have been executed previously. I don't know of anything in LLVM that does this today, but it would become an important invariant.</div><div>4) Work a lot harder to do internalizing and removing of this restriction.</div><div><br></div><div>Pretty horrible. But I think it is correct.</div><div><br></div><div>As a slight modification to #1 and #2, we could have a very carefully crafted deduction rule where we only deduce function attributes for functions prior to any modification of their function bodies. Such attributes should be conservatively correct because we would never lift new code into the function bodies. This would at least allow us to do bottom-up deduction to catch interprocedural cases. But it would become incredibly subtle that this is only valid prior to *any* transformations of the comdat-containing functions.</div><div><br></div><div>I'm starting to think this subtle rule might be worth it. But I'm frankly terrified by the implications.</div></div><br><div class="gmail_quote"><div dir="ltr">On Wed, Feb 24, 2016 at 8:13 PM Philip Reames via llvm-dev <<a href="mailto:llvm-dev@lists.llvm.org">llvm-dev@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
<br>
On 02/24/2016 08:10 PM, Duncan P. N. Exon Smith via llvm-dev wrote:<br>
>> On 2016-Feb-24, at 19:46, Sanjoy Das <<a href="mailto:sanjoy@playingwithpointers.com" target="_blank">sanjoy@playingwithpointers.com</a>> wrote:<br>
>><br>
>> On Wed, Feb 24, 2016 at 7:38 PM, Chandler Carruth <<a href="mailto:chandlerc@google.com" target="_blank">chandlerc@google.com</a>> wrote:<br>
>>> On Wed, Feb 24, 2016 at 7:34 PM Duncan P. N. Exon Smith<br>
>>> <<a href="mailto:dexonsmith@apple.com" target="_blank">dexonsmith@apple.com</a>> wrote:<br>
>>>><br>
>>>>> On 2016-Feb-24, at 19:17, Chandler Carruth <<a href="mailto:chandlerc@google.com" target="_blank">chandlerc@google.com</a>> wrote:<br>
>>>>><br>
>>>>> On Wed, Feb 24, 2016 at 7:10 PM Sanjoy Das via llvm-dev<br>
>>>>> <<a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a>> wrote:<br>
>>>>> On Wed, Feb 24, 2016 at 6:51 PM, Duncan P. N. Exon Smith<br>
>>>>> <<a href="mailto:dexonsmith@apple.com" target="_blank">dexonsmith@apple.com</a>> wrote:<br>
>>>>>>> If we do not inline @foo(), and instead re-link the call site in<br>
>>>>>>> @main<br>
>>>>>>> to some non-optimized copy (or differently optimized copy) of @foo,<br>
>>>>>>> then it is possible for the program to have the behavior {print("Y");<br>
>>>>>>> print ("X")}, which was disallowed in the earlier program.<br>
>>>>>>><br>
>>>>>>> In other words, opt refined the semantics of @foo() (i.e. reduced the<br>
>>>>>>> set of behaviors it may have) in ways that would make later<br>
>>>>>>> optimizations invalid if we de-refine the implementation of @foo().<br>
>>>>>> I'm probably missing something obvious here. How could the result of<br>
>>>>>> `%t0 != %t1` be different at optimization time in one file than from<br>
>>>>>> runtime in the "real" implementation? Doesn't this make the CSE<br>
>>>>>> invalid?<br>
>>>>> `%t0` and `%t1` are "allowed" to "always be the same", i.e. an<br>
>>>>> implementation of @foo that always feeds in the same<br>
>>>>> value for `%t0` and `%t1` is a valid implementation (which is why the<br>
>>>>> CSE was valid); but it is not the *only* valid implementation. If I<br>
>>>>> don't CSE the two load instructions (also a valid thing to do), and<br>
>>>>> this is a second thread writing to `%par`, then the two values loaded<br>
>>>>> can be different, and you could end up printing `"X"` in `@foo`.<br>
>>>>><br>
>>>>> Did that make sense?<br>
>>>> Yes. To be sure I understand the scope: this is only a problem for<br>
>>>> atomics, correct? (Because multi-threaded behaviour with other globals<br>
>>>> is UB?)<br>
>>>><br>
>>>>>> Does linkonce_odr linkage have the same problem?<br>
>>>>>> - If so, do you want to change it too?<br>
>>>>>> - Else, why not?<br>
>>>>> Going by the specification in the LangRef, I'd say it depends on how<br>
>>>>> you define "definitive". If you're allowed to replace the body of a<br>
>>>>> function with a differently optimized body, then the above problem<br>
>>>>> exists.<br>
>>>>><br>
>>>>> I believe that is the case, and I strongly believe the problem you<br>
>>>>> outline exists for linkonce_odr exactly as it does for available_externally.<br>
>>>>><br>
>>>>> Which is what makes this scary: every C++ inline function today can<br>
>>>>> trigger this.<br>
>>>> Every C/C++ inline or template function. But only the ones that use<br>
>>>> atomics, right?<br>
>>><br>
>>> Well, with *this* example...<br>
>> Atomic are one source of non-determinism that compilers can reason<br>
>> about. I don't know if the following snippet is well defined or not,<br>
>> but you could have similar issues with<br>
>><br>
>><br>
>> void foo() {<br>
>> int *p = malloc(sizeof(int));<br>
>> if (*p < 10) print("X");<br>
>> }<br>
>><br>
>> or (again, I don't know if this is actually well defined)<br>
>><br>
>> void foo() {<br>
>> int t; // it is probably reasonable to fold compares with<br>
>> ptrtoint(alloca) to undef<br>
>> if ((intptr_t)(&t) < 10) print("X");<br>
>> }<br>
>><br>
> The first one at least is UB, but as Richard pointed out the scope<br>
> is certainly broader than atomics (it's not even just well-defined<br>
> non-deterministism).<br>
><br>
> I'm kind of terrified by the implications.<br>
Me too. :(<br>
><br>
>> -- Sanjoy<br>
>><br>
>>>><br>
>>>> Not that I'm sure that will end up being a helpful distinction.<br>
>>><br>
>>> Right. See Richard's comment. I think that sums up the real issue here. =/<br>
> _______________________________________________<br>
> LLVM Developers mailing list<br>
> <a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a><br>
> <a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev</a><br>
<br>
_______________________________________________<br>
LLVM Developers mailing list<br>
<a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev</a><br>
</blockquote></div>