On Wed, Jan 15, 2020 at 09:52:57PM +0100, Jakub Jelinek wrote:
> This looks wrong. For one, this function is used for two purposes now and
> you tweak it for one, but more importantly, whether he initial stmt
> you see is a PHI or not can't make a difference, how is that case e.g.
> different from _1 = PHI <_3, _4>; _2 = _1 + 1; and asking about _2?
> For _1, you'd use (correctly) the maximum, but if called on _2, you'd ask
> (wrongly) for minimum instead of maximum.
And now with testcases. strlenopt-95.c shows the above.
> This also looks like a hack to shut up the particular testcases instead of
> really playing with what the IL provides. Instead of the unions, consider
> e.g. C++ placement new, have a pointer to a buffer into which you placement
> new one structure, take address of some member in it, pass it to something,
> if it doesn't have a destructor do a C++ placement new into the same buffer
> but with different structure, take address of a different member with the
> same address as the first member, do the str*cmp on it that invokes this
> stuff. SCCVN will (likely) find out that the values of those two pointers
> are the same and just use the former pointer in the latter case.
And strlenopt-93.C shows the latter. strlenopt-94.C is similar, just to
show that it breaks equally badly with non-PODs that will be constructed by
placement new and destructed later.
Jakub
__attribute__((noipa)) int
barrier_copy (char *x, int y)
{
asm volatile ("" : : "g" (x), "g" (y) : "memory");
if (y == 0)
__builtin_strcpy (x, "abcd");
return y;
}
__attribute__((noipa)) char *
test_2 (int x)
{
char *p;
if (x)
p = __builtin_malloc (4);
else
p = __builtin_calloc (16, 1);
char *q = p + 2;
if (barrier_copy (q, x))
return p;
if (__builtin_strcmp (q, "abcd") != 0)
__builtin_abort ();
return p;
}
int
main ()
{
__builtin_free (test_2 (0));
__builtin_free (test_2 (1));
return 0;
}
#include <new>
struct S1 { char a[2]; char b[2]; char c[2]; };
struct S2 { char d[6]; };
__attribute__((noipa)) void
foo (char *b)
{
b[0] = 1;
b[1] = 2;
asm volatile ("" : : "g" (b) : "memory");
}
__attribute__((noipa)) void
bar (char *d)
{
__builtin_memcpy (d, "cde", 4);
asm volatile ("" : : "g" (d) : "memory");
}
__attribute__((noipa)) void
baz (char *buf)
{
S1 *s1 = new (buf) S1;
char *p = (char *) &s1->b;
foo (p);
S2 *s2 = new (buf) S2;
char *q = (char *) &s2->d[2];
bar (q);
if (__builtin_strcmp (q, "cde"))
__builtin_abort ();
}
int
main ()
{
union U { S1 s1; S2 s2; char buf[sizeof (S1) > sizeof (S2) ? sizeof (S1) :
sizeof (S2)]; } u;
baz (u.buf);
return 0;
}
#include <new>
struct S1 { char a[2]; char b[2]; char c[2]; S1 () { a[0] = 0; b[0] = 0; c[0] =
0; }; ~S1 () {} };
struct S2 { char d[6]; S2 () { d[0] = 0; d[2] = 0; } ~S2 () {} };
__attribute__((noipa)) void
foo (char *b)
{
b[0] = 1;
b[1] = 2;
asm volatile ("" : : "g" (b) : "memory");
}
__attribute__((noipa)) void
bar (char *d)
{
__builtin_memcpy (d, "cde", 4);
asm volatile ("" : : "g" (d) : "memory");
}
__attribute__((noipa)) void
baz (char *buf)
{
S1 *s1 = new (buf) S1 ();
char *p = (char *) &s1->b;
foo (p);
s1->~S1 ();
S2 *s2 = new (buf) S2 ();
char *q = (char *) &s2->d[2];
bar (q);
if (__builtin_strcmp (q, "cde"))
__builtin_abort ();
s2->~S2 ();
}
int
main ()
{
char buf[sizeof (S1) > sizeof (S2) ? sizeof (S1) : sizeof (S2)];
baz (buf);
return 0;
}