[Bug rtl-optimization/63259] Detecting byteswap sequence

olegendo at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Sun Dec 14 23:53:00 GMT 2014


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

--- Comment #9 from Oleg Endo <olegendo at gcc dot gnu.org> ---
(In reply to thopre01 from comment #7)
> (In reply to Oleg Endo from comment #6)
> > With r218705 on SH (-O2 -m4 -ml) I get the following:
> > 
> > unsigned short test_099 (unsigned short a, unsigned short b)
> > {
> >   return (((a & 0xFF00) >> 8) | ((a & 0xFF) << 8));
> > }
> > 
> > compiles to:
> >         extu.w	r4,r4
> >         rts
> >         swap.b	r4,r0
> 
> This one looks ok except for the zero-extension. Is the swap.b instruction
> limited to 32 bit values?

Yes, in sh.md swap.b is defined for SImode values only.  But never mind the
extu.w, it's an SH ABI thing (PR 52441).

> 
> > 
> > 
> > unsigned short test_08 (unsigned short a, unsigned short b)
> > {
> >   return b + (((a & 0xFF00) >> 8) | ((a & 0xFF) << 8));
> > }
> > 
> > compiles to:
> >         extu.w  r4,r4
> >         mov     r4,r0
> >         shll8   r4
> >         shlr8   r0
> >         or      r0,r4
> >         add     r4,r5
> >         rts
> >         extu.w  r5,r0
> 
> Strange, could you show the output of -fdump-tree-bswap?

Not so strange at all.  After looking at the RTL dumps, I've noticed that the
swap.b insn is generated by the combine pass.  I've got a few combine patterns
for matching byte swaps on SH.  The pattern for swap.b doesn't combine well
with other ops around/on it.  -fdump-tree-bswap says:

;; Function test_08 (test_08, funcdef_no=1, decl_uid=1333, cgraph_uid=1,
symbol_order=1)

test_08 (short unsigned int a, short unsigned int b)
{
  short unsigned int _2;
  signed short _3;
  int _4;
  int _5;
  signed short _6;
  signed short _7;
  short unsigned int _8;
  short unsigned int _10;

  <bb 2>:
  _2 = a_1(D) >> 8;
  _3 = (signed short) _2;
  _4 = (int) a_1(D);
  _5 = _4 << 8;
  _6 = (signed short) _5;
  _7 = _3 | _6;
  _8 = (short unsigned int) _7;
  _10 = _8 + b_9(D);
  return _10;

}


> > Byte swapping of signed short types seems to be not working:
> > 
> > short test_func_111 (short a, short b, short c)
> > {
> >   return (((a & 0xFF00) >> 8) | ((a & 0xFF) << 8));
> > }
> > 
> >         exts.w  r4,r4
> >         mov     r4,r0
> >         shlr8   r0
> >         extu.b  r0,r0
> >         shll8   r4
> >         or      r0,r4
> >         rts
> >         exts.w  r4,r0
> 
> That's expected. Think about what happens if a = 0x8001. Doing a right shift
> by 8 bit would give 0xFF80 (due to the most significant bit being 1). The
> right part of the bitwise OR would give 0x0100 as expected and the result
> would be 0xFF80, so not a byte swap. It would work with an int though as the
> highest bit would then be 0, or with unsigned short as a right shift would
> introduce 0 in the most significant bits.

As Andreas mentioned, 'a' is promoted to int, so this should be a byte swap.


More information about the Gcc-bugs mailing list