This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Fix the one entry mem{{,p}cpy,move,set} optimization aliasing issues (PR middle-end/29272)
- From: Mike Stump <mrs at apple dot com>
- To: Mark Mitchell <mark at codesourcery dot com>
- Cc: Jakub Jelinek <jakub at redhat dot com>, gcc-patches at gcc dot gnu dot org
- Date: Fri, 29 Sep 2006 16:12:47 -0700
- Subject: Re: [PATCH] Fix the one entry mem{{,p}cpy,move,set} optimization aliasing issues (PR middle-end/29272)
- References: <20060929075035.GQ20982@devserv.devel.redhat.com> <451D5AEA.4040401@codesourcery.com>
On Sep 29, 2006, at 10:42 AM, Mark Mitchell wrote:
In C++, placement new makes things even more complicated, as things
like:
buf = new char[4096];
s = new (buf) S();
s->~S();
t = new (buf) T();
Actually, it is worse:
char b[4096];
int *ip = b;
ip += 16
p &= ~15;
foo(*(float*)ip)
Starts the lifetime of a float object, without the placement
operator. We can so start the lifetime of any object with a trivial
constructor as well. We don't need a placement operator to so start
the lifetime.
int i, j, k;
*(float *)&i = 4.3;
*(flloat *)&j = *(float*)&i;
mempcy (&k, &j, 4)
here, memcpy doesn't copy an int, but rather a float (in C++). The
dynamic type is a runtime property in C++, and C++ is what our
understanding of the C rules are, if they had been written down and
made sense.
If one might have had an int in i, then the memcpy would also alias
ints. If there is no way it could have had an int, then it would be
fine to just treat it as a float. Compare:
{
int i, j, k;
i = 12;
if (random()) {
*(float *)&i = 4.3;
*(flloat *)&j = *(float*)&i;
}
mempcy (&k, &j, 4);
}
Here, the alias set would be int|float, if you wanted to optimize
aggressively.
I think the best way to handle this is conservatively: use alias
set zero for all reads/writes from things like memcpy, so that we
don't create any no-aliasing expectations in the compiler.
Kinda agree. I'm all for optimization people taking things to the
limit, but I'd rather have them understand the language rules first.
One can add additional things, but you have to be very, very
careful. If something is later read as a float, then the previous
store can be promoted to a float store, or if something is stored as
a float, than the later read can be thought of as a float read.
I think that trying to get clever about the effective types here is
likely to break code, and I'm not at all confident that the rules
in the standard are even self-consistent.
The C++ rules should be well thought out and correct. I'll note,
they are slightly different from the C rules. For example, the
effective type in C of int i, is always int. In C++, the dynamic
type isn't always int.
I think the reasoning to be used (C++ rules) for the PR is that the
value stored when we do:
__builtin_memcpy (&node->next, &pool, sizeof(struct Node*));
is of type character (conservatively), or, if we want to optimize,
the type read from that location when it is next accessed. That type
in the program is int, not Node*. If the alias set had been int, 0
would not have been returned.