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

--- Comment #4 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
I guess the first question is why do we optimize unsigned / 2 into unsigned >>
1 during GIMPLE opts only in VRP (evrp etc.) as can be seen with just compiling
it with -O1, even optimized dump has
  x_9 = x_3(D) / 2;
and only expansion turns that into
(insn 13 12 0 (parallel [
            (set (reg/v:SI 99 [ x ])
                (lshiftrt:SI (reg/v:SI 101 [ x ])
                    (const_int 1 [0x1])))
            (clobber (reg:CC 17 flags))
        ]) "pr118637.c":5:12 -1
     (expr_list:REG_EQUAL (udiv:SI (reg/v:SI 101 [ x ])
            (const_int 2 [0x2]))
        (nil)))
So e.g. with -O1 we don't optimize
void link_error (void);

void
foo (unsigned x)
{
  if (x / 2 != x >> 1)
    link_error ();
}
until RTL.

The r8-2064-g8d1628eb33d4f5 optimization is sane IMHO; and user could have
written it that way as well.

Consider
unsigned
foo (unsigned x)
{
  unsigned result = 0;
  while (x /= 2)
    ++result;
  return result;
}

unsigned
bar (unsigned x)
{
  unsigned result = 0;
  while (x >>= 1)
    ++result;
  return result;
}

unsigned
baz (unsigned x)
{
  unsigned result = 0, t;
  while ((t = x, x /= 2, t > 1))
    ++result;
  return result;
}

unsigned
qux (unsigned x)
{
  unsigned result = 0, t;
  while ((t = x, x >>= 1, t > 1))
    ++result;
  return result;
}

unsigned
fred (unsigned x)
{
  unsigned result = 0;
  while (x > 1)
    x /= 2, ++result;
  return result;
}

unsigned
corge (unsigned x)
{
  unsigned result = 0;
  while (x > 1)
    ++result, x >>= 1;
  return result;
}
I think all of these compute the same thing, but we only pattern recognize the
first one and clang only pattern recognizes the first two.

Reply via email to