[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