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

Jakub Jelinek <jakub at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jakub at gcc dot gnu.org

--- Comment #2 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
The testcase seems to be optimized into return a >> b; and already e.g. GCC 4.4
does that.
So it is unclear why this has been reported and what difference you found.

That said, given:
unsigned
foo (unsigned a, unsigned b)
{
  return a / (unsigned long long) (1U << b);
}

unsigned
bar (unsigned a, unsigned b)
{
  return a / (1U << b);
}

unsigned
baz (unsigned a, unsigned b)
{
  unsigned long long c = 1U << b;
  return a / c;
}

I see that while we optimize foo and bar into a >> b, by the:
/* (A / (1 << B)) -> (A >> B).
   Only for unsigned A.  For signed A, this would not preserve rounding
   toward zero.
   For example: (-1 / ( 1 << B)) !=  -1 >> B.
   Also also widening conversions, like:
   (A / (unsigned long long) (1U << B)) -> (A >> B)
   or
   (A / (unsigned long long) (1 << B)) -> (A >> B).
   If the left shift is signed, it can be done only if the upper bits
   of A starting from shift's type sign bit are zero, as
   (unsigned long long) (1 << 31) is -2147483648ULL, not 2147483648ULL,
   so it is valid only if A >> 31 is zero.  */
but for baz we actually perform the shift in the wider mode unnecessarily,
because both operands are zero-extended from 32 bits.

Given:
unsigned
qux (unsigned a, unsigned b)
{
  unsigned long long c = a;
  unsigned long long d = b;
  return c / d;
}

unsigned
corge (unsigned a, unsigned b)
{
  return ((unsigned long long) a) / (unsigned long long) b;
}
we only optimize it in corge to return a / b; and not in qux, so some
fold-const optimization is not done on GIMPLE.

Reply via email to