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

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

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

--- Comment #2 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
Simplified testcase:
static inline unsigned
bar (unsigned x)
{
  return ((x & 0x000000ff) << 24) | ((x & 0x0000ff00) << 8)
         | ((x & 0x00ff0000) >> 8) | ((x & 0xff000000) >> 24);
}

unsigned
foo (unsigned p, unsigned q)
{
  p &= ~0x1ffff80U;
  p |= bar ((q << 7) & 0x1ffff80U);
  return p;
}

The problem is that with |= instead of += the reassoc pass is invoked first and
reassociates the many | operands and then the bswap pass can't recognize the
pattern.
So, either we should consider moving the bswap pass 6 passes earlier (i.e.
before reassoc1), or if we want to catch that we'd need to be able to recognize
| operands unrelated to the bswap pattern mixed with | operands related to
that, and replace just the ones related to the bswap and leave the others in.
One could have also several bswap patterns results ored together with reassoc
reordering it, say for p |= bar ((q << 7) & 0x1ffff80U) | bar ((r << 7) &
0x1ffff80U); above with another unsigned r argument.  In that case it would be
better to or the two bar arguments and bswap the result, i.e.
  p |= __builtin_bswap32 (((q << 7) & 0x1ffff80U) | ((r << 7) & 0x1ffff80U));

Reply via email to