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.