[PATCH] Fix the one entry mem{{,p}cpy,move,set} optimization aliasing issues (PR middle-end/29272)
Mike Stump
mrs@apple.com
Sat Sep 30 00:21:00 GMT 2006
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.
More information about the Gcc-patches
mailing list