[llvm-dev] Placement new and TBAA
Sanjoy Das via llvm-dev
llvm-dev at lists.llvm.org
Fri Nov 25 21:07:34 PST 2016
Hi,
On Sat, Nov 26, 2016 at 9:53 AM, Mehdi Amini <mehdi.amini at apple.com> wrote:
> 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
More information about the llvm-dev
mailing list