<p dir="ltr"> The position most compilers take is the the access must be visibly through a union if you want it to work.  Otherwise, it's not possible to use tbaa really at all.  Move your function f to another file, for example, and you simply could never tell.  Some will give you a little more, but you are pushing your luck</p>
<p dir="ltr">This was discussed in depth in the thread I quoted, and has GCC mailing list threads going back to before llvm existed :).<br>
Note that there are rules about touching members in a union other than the first one you set, but pretty much everyone guarantees type punning through unions to work.<br>
</p>
<br><div class="gmail_quote"><div dir="ltr">On Fri, Nov 25, 2016, 9:07 PM Sanjoy Das <<a href="mailto:sanjoy@playingwithpointers.com">sanjoy@playingwithpointers.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi,<br class="gmail_msg">
<br class="gmail_msg">
On Sat, Nov 26, 2016 at 9:53 AM, Mehdi Amini <<a href="mailto:mehdi.amini@apple.com" class="gmail_msg" target="_blank">mehdi.amini@apple.com</a>> wrote:<br class="gmail_msg">
> The PR says "passes with -fno-strict-aliasing”, my understanding is that it<br class="gmail_msg">
> is failing only with the TBAA indeed.<br class="gmail_msg">
><br class="gmail_msg">
> You don’t need the main and the union to reproduce, extracting foo() alone<br class="gmail_msg">
> in its single own file is enough:<br class="gmail_msg">
><br class="gmail_msg">
> void *operator new(decltype(sizeof 0), void *) noexcept;<br class="gmail_msg">
> float *qq;<br class="gmail_msg">
> void foo(int *p, int *q, long unk) {<br class="gmail_msg">
>    for (long i = 0; i < unk; ++i) {<br class="gmail_msg">
>       ++*p;<br class="gmail_msg">
>       qq = new (static_cast<void *>(&q[i])) float(42);<br class="gmail_msg">
>    }<br class="gmail_msg">
> }<br class="gmail_msg">
><br class="gmail_msg">
> LICM will get the store to p out of the loop, conceptually turning it into:<br class="gmail_msg">
><br class="gmail_msg">
> void foo(int *p, int *q, long unk) {<br class="gmail_msg">
>    for (long i = 0; i < unk; ++i) {<br class="gmail_msg">
>       qq = new (static_cast<void *>(&q[i])) float(42);<br class="gmail_msg">
>    }<br class="gmail_msg">
>    ++*p;<br class="gmail_msg">
> }<br class="gmail_msg">
><br class="gmail_msg">
><br class="gmail_msg">
> Now I don’t know if the use of placement new in this example is legal in the<br class="gmail_msg">
> first place. I thought calling delete before using placement new was<br class="gmail_msg">
> mandatory.<br class="gmail_msg">
<br class="gmail_msg">
So if you:<br class="gmail_msg">
<br class="gmail_msg">
 1. override operator delete to do nothing for that type (so that the<br class="gmail_msg">
    placement new actually has unfreed backing storage to re-use).<br class="gmail_msg">
 2. have an empty destructor.<br class="gmail_msg">
<br class="gmail_msg">
and have the source program be<br class="gmail_msg">
<br class="gmail_msg">
  void *operator new(decltype(sizeof 0), void *) noexcept;<br class="gmail_msg">
  float *qq;<br class="gmail_msg">
  void foo(int *p, int *q, long unk) {<br class="gmail_msg">
     // unk = 1<br class="gmail_msg">
     for (long i = 0; i < unk; ++i) {<br class="gmail_msg">
        ++*p;<br class="gmail_msg">
        delete &q[i];  // since i is only ever 0, this does not<br class="gmail_msg">
              // delete a derived pointer<br class="gmail_msg">
        qq = new (static_cast<void *>(&q[i])) float(42);<br class="gmail_msg">
     }<br class="gmail_msg">
  }<br class="gmail_msg">
<br class="gmail_msg">
then I suspect we'll have the same problem after the destructor and<br class="gmail_msg">
the operator delete for that type has been inlined away.<br class="gmail_msg">
<br class="gmail_msg">
> CC Sanjoy, since he looked into TBAA recently and it reminds me a similar<br class="gmail_msg">
> test case he mentioned, not with placement new but with a call to a function<br class="gmail_msg">
> taking int * and float *, and passing the same address (call site was<br class="gmail_msg">
> union).<br class="gmail_msg">
<br class="gmail_msg">
The case I was talking about was something like:<br class="gmail_msg">
<br class="gmail_msg">
// C11 source file.<br class="gmail_msg">
<br class="gmail_msg">
union S {<br class="gmail_msg">
  int i;<br class="gmail_msg">
  float f;<br class="gmail_msg">
};<br class="gmail_msg">
<br class="gmail_msg">
void f(int* i, float *f) {<br class="gmail_msg">
  *i = 20;<br class="gmail_msg">
  *f = 40.0;<br class="gmail_msg">
}<br class="gmail_msg">
<br class="gmail_msg">
void g() {<br class="gmail_msg">
  union S s;<br class="gmail_msg">
  f(&s.i, &s.f);<br class="gmail_msg">
}<br class="gmail_msg">
<br class="gmail_msg">
<br class="gmail_msg">
At least cursorily this looked well defined in C++ to me -- f should<br class="gmail_msg">
first write int(20) and then float(40.0) to the same location legally.<br class="gmail_msg">
However clang emits tbaa such that LLVM concludes that in f, the store<br class="gmail_msg">
to i and the store to f don't alias.<br class="gmail_msg">
<br class="gmail_msg">
However, I'm not very confident in the "this looked well defined"<br class="gmail_msg">
reading.  I did not consult the standard, but instead relied on second<br class="gmail_msg">
hand stackoverflow answers, so I won't be surprised to hear that I was<br class="gmail_msg">
wrong about this.  Actually I'm never surprised to hear that I'm<br class="gmail_msg">
wrong, but I'll be especially less surprised in this case. :)<br class="gmail_msg">
<br class="gmail_msg">
Thanks!<br class="gmail_msg">
-- Sanjoy<br class="gmail_msg">
</blockquote></div>