Hi,
The PR says "passes with -fno-strict-aliasing”, my understanding is that it
is failing only with the TBAA indeed.
You don’t need the main and the union to reproduce, extracting foo() alone
in its single own file is enough:
void *operator new(decltype(sizeof 0), void *) noexcept;
float *qq;
void foo(int *p, int *q, long unk) {
for (long i = 0; i < unk; ++i) {
++*p;
qq = new (static_cast<void *>(&q[i])) float(42);
}
}
LICM will get the store to p out of the loop, conceptually turning it into:
void foo(int *p, int *q, long unk) {
for (long i = 0; i < unk; ++i) {
qq = new (static_cast<void *>(&q[i])) float(42);
}
++*p;
}
Now I don’t know if the use of placement new in this example is legal in the
first place. I thought calling delete before using placement new was
mandatory.
So if you:
1. override operator delete to do nothing for that type (so that the
placement new actually has unfreed backing storage to re-use).
2. have an empty destructor.
and have the source program be
void *operator new(decltype(sizeof 0), void *) noexcept;
float *qq;
void foo(int *p, int *q, long unk) {
// unk = 1
for (long i = 0; i < unk; ++i) {
++*p;
delete &q[i]; // since i is only ever 0, this does not
// delete a derived pointer
qq = new (static_cast<void *>(&q[i])) float(42);
}
}
then I suspect we'll have the same problem after the destructor and
the operator delete for that type has been inlined away.
CC Sanjoy, since he looked into TBAA recently and it reminds me a similar
test case he mentioned, not with placement new but with a call to a function
taking int * and float *, and passing the same address (call site was
union).
The case I was talking about was something like:
// C11 source file.
union S {
int i;
float f;
};
void f(int* i, float *f) {
*i = 20;
*f = 40.0;
}
void g() {
union S s;
f(&s.i, &s.f);
}
At least cursorily this looked well defined in C++ to me -- f should
first write int(20) and then float(40.0) to the same location legally.
However clang emits tbaa such that LLVM concludes that in f, the store
to i and the store to f don't alias.
However, I'm not very confident in the "this looked well defined"
reading. I did not consult the standard, but instead relied on second
hand stackoverflow answers, so I won't be surprised to hear that I was
wrong about this. Actually I'm never surprised to hear that I'm
wrong, but I'll be especially less surprised in this case. 
Thanks!
-- Sanjoy