https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94988

--- Comment #2 from Richard Biener <rguenth at gcc dot gnu.org> ---
(In reply to Richard Biener from comment #1)
> Ah, forgot to update this testcase.  This is another instance of PR57359,
> that is, we may not sink the store to b across the store to *b since b may
> point
> to itself and with j == 1 we'd change
> 
>  b = b + 2;
>  *b = x;
> 
> to
> 
>  *b = x;
>  b = b + 2;
> 
> note there's a twist for this particular case, namely the preceeding load
> of 'b' gives us knowledge about the dynamic type of 'b' which means we
> could use that to assess that we _can_ exchange the stores.
> 
> But that logic is not implemented.
> 
> I'll see how to do that.

OK, we can't.  Consider the following which we miscompile with GCC 10
but which is fixed on trunk.  bar () is simply the inner loop of
bar in the pr64110.c testcase.  GCC 10 and earlier transform

  b++;
  *b = x;

to

  tem = b + 1;
  *b = x;
  b = tem;

which is wrong with b == &b, the *b = x store re-purposes the
storage in 'b'.

short *b;

void __attribute__((noipa))
bar (short x, int j)
{
  for (int i = 0; i < j; ++i)
    *b++ = x;
}

int
main()
{
  b = (short *)&b;
  bar (0, 1);
  if ((short)(unsigned long)b != 0)
    __builtin_abort ();
  return 0;
}

Now the only thing that can be done (as noted in PR57359) is
re-materializing _both_ stores on the exit.   Thus turn

  for (int i = 0; i < j; ++i)
    {
      tem = b;
      tem = tem + 1;
      b = tem;
      *tem = x;
    }

into

  tem = b;
  for (int i = 0; i < j; ++i)
    {
      tem = tem + 1;
      *tem = x;
    }
  b = tem;
  *tem = x;

when applying store-motion.  Note this only works when b is written to
unconditionally.  It also needs some kind of a cost model I guess...

Reply via email to